Browse Source

[master] Finished merge of trac5033 (migrate D2client)

Francis Dupont 8 years ago
parent
commit
decb410509
41 changed files with 7505 additions and 4974 deletions
  1. 2 0
      doc/Makefile.am
  2. 77 0
      doc/examples/kea4/with-ddns.json
  3. 82 0
      doc/examples/kea6/with-ddns.json
  4. 4 3
      doc/guide/dhcp4-srv.xml
  5. 4 3
      doc/guide/dhcp6-srv.xml
  6. 1108 819
      src/bin/dhcp4/dhcp4_lexer.cc
  7. 227 0
      src/bin/dhcp4/dhcp4_lexer.ll
  8. 1561 1280
      src/bin/dhcp4/dhcp4_parser.cc
  9. 370 197
      src/bin/dhcp4/dhcp4_parser.h
  10. 176 22
      src/bin/dhcp4/dhcp4_parser.yy
  11. 17 2
      src/bin/dhcp4/json_config_parser.cc
  12. 8 0
      src/bin/dhcp4/parser_context.cc
  13. 19 4
      src/bin/dhcp4/parser_context.h
  14. 1 1
      src/bin/dhcp4/position.hh
  15. 1 1
      src/bin/dhcp4/stack.hh
  16. 1 1
      src/bin/dhcp4/tests/config_parser_unittest.cc
  17. 2 2
      src/bin/dhcp4/tests/d2_unittest.cc
  18. 11 28
      src/bin/dhcp4/tests/fqdn_unittest.cc
  19. 2 1
      src/bin/dhcp4/tests/parser_unittest.cc
  20. 1133 853
      src/bin/dhcp6/dhcp6_lexer.cc
  21. 227 0
      src/bin/dhcp6/dhcp6_lexer.ll
  22. 1566 1336
      src/bin/dhcp6/dhcp6_parser.cc
  23. 294 132
      src/bin/dhcp6/dhcp6_parser.h
  24. 176 22
      src/bin/dhcp6/dhcp6_parser.yy
  25. 17 2
      src/bin/dhcp6/json_config_parser.cc
  26. 1 1
      src/bin/dhcp6/location.hh
  27. 8 0
      src/bin/dhcp6/parser_context.cc
  28. 19 4
      src/bin/dhcp6/parser_context.h
  29. 1 1
      src/bin/dhcp6/position.hh
  30. 1 1
      src/bin/dhcp6/stack.hh
  31. 2 2
      src/bin/dhcp6/tests/d2_unittest.cc
  32. 12 28
      src/bin/dhcp6/tests/fqdn_unittest.cc
  33. 1 0
      src/bin/dhcp6/tests/parser_unittest.cc
  34. 11 1
      src/lib/dhcpsrv/cfgmgr.cc
  35. 6 1
      src/lib/dhcpsrv/cfgmgr.h
  36. 238 148
      src/lib/dhcpsrv/parsers/dhcp_parsers.cc
  37. 29 45
      src/lib/dhcpsrv/parsers/dhcp_parsers.h
  38. 10 6
      src/lib/dhcpsrv/srv_config.cc
  39. 21 2
      src/lib/dhcpsrv/srv_config.h
  40. 55 22
      src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
  41. 4 3
      src/lib/dhcpsrv/tests/srv_config_unittest.cc

+ 2 - 0
doc/Makefile.am

@@ -20,6 +20,7 @@ nobase_dist_doc_DATA += examples/kea4/pgsql-reservations.json
 nobase_dist_doc_DATA += examples/kea4/reservations.json
 nobase_dist_doc_DATA += examples/kea4/reservations.json
 nobase_dist_doc_DATA += examples/kea4/several-subnets.json
 nobase_dist_doc_DATA += examples/kea4/several-subnets.json
 nobase_dist_doc_DATA += examples/kea4/single-subnet.json
 nobase_dist_doc_DATA += examples/kea4/single-subnet.json
+nobase_dist_doc_DATA += examples/kea4/with-ddns.json
 nobase_dist_doc_DATA += examples/kea6/advanced.json
 nobase_dist_doc_DATA += examples/kea6/advanced.json
 nobase_dist_doc_DATA += examples/kea6/backends.json
 nobase_dist_doc_DATA += examples/kea6/backends.json
 nobase_dist_doc_DATA += examples/kea6/classify.json
 nobase_dist_doc_DATA += examples/kea6/classify.json
@@ -35,6 +36,7 @@ nobase_dist_doc_DATA += examples/kea6/several-subnets.json
 nobase_dist_doc_DATA += examples/kea6/simple.json
 nobase_dist_doc_DATA += examples/kea6/simple.json
 nobase_dist_doc_DATA += examples/kea6/softwire46.json
 nobase_dist_doc_DATA += examples/kea6/softwire46.json
 nobase_dist_doc_DATA += examples/kea6/stateless.json
 nobase_dist_doc_DATA += examples/kea6/stateless.json
+nobase_dist_doc_DATA += examples/kea6/with-ddns.json
 
 
 devel:
 devel:
 	mkdir -p html
 	mkdir -p html

+ 77 - 0
doc/examples/kea4/with-ddns.json

@@ -0,0 +1,77 @@
+# This is an example configuration file for the DHCPv4 server in Kea.
+# It is a basic scenario with one IPv4 subnet configured but with DDNS
+# enabled. 
+
+{ "Dhcp4":
+
+{
+# Kea is told to listen on ethX interface only.
+  "interfaces-config": {
+    "interfaces": [ "ethX" ]
+  },
+
+# We need to specify the the database used to store leases. As of
+# September 2016, four database backends are supported: MySQL,
+# PostgreSQL, Cassandra, and the in-memory database, Memfile.
+# We'll use memfile  because it doesn't require any prior set up.
+  "lease-database": {
+      "type": "memfile",
+      "lfc-interval": 3600
+  },
+
+# Addresses will be assigned with a lifetime of 4000 seconds.
+  "valid-lifetime": 4000,
+
+# Renew and rebind timers are commented out. This implies that options
+# 58 and 59 will not be sent to the client. In this case it is up to
+# the client to pick the timer values according to RFC2131. Uncomment the
+# timers to send these options to the client.
+#  "renew-timer": 1000,
+#  "rebind-timer": 2000,
+
+# The following list defines subnets. We have only one subnet
+# here. We tell Kea that it is directly available over local interface.
+  "subnet4": [
+    {
+       "pools": [ { "pool":  "192.0.2.1 - 192.0.2.200" } ],
+       "subnet": "192.0.2.0/24",
+       "interface": "ethX"
+    }
+  ],
+
+# Enable dynamic DNS updates
+  "dhcp-ddns" : {
+        "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,
+        "override-no-update" : true,
+        "override-client-update" : true,
+        "replace-client-name" : "when-present",
+        "generated-prefix" : "test.prefix",
+        "qualifying-suffix" : "test.suffix."
+    }
+},
+
+# The following configures logging. It assumes that messages with at least
+# informational level (info, warn, error and fatal) should be logged to stdout.
+"Logging": {
+    "loggers": [
+        {
+            "name": "kea-dhcp4",
+            "output_options": [
+                {
+                    "output": "stdout"
+                }
+            ],
+            "severity": "INFO"
+        }
+    ]
+}
+
+}

+ 82 - 0
doc/examples/kea6/with-ddns.json

@@ -0,0 +1,82 @@
+# This is an example configuration file for DHCPv6 server in Kea.
+# It's a basic scenario with one IPv6 subnet configured. It is
+# assumed that one subnet (2001:db8:1::/64 is available directly
+# over ethX interface.
+
+{ "Dhcp6":
+
+{
+# Kea is told to listen on ethX interface only.
+  "interfaces-config": {
+    "interfaces": [ "ethX" ]
+  },
+
+# We need to specify the the database used to store leases. As of
+# September 2016, four database backends are supported: MySQL,
+# PostgreSQL, Cassandra, and the in-memory database, Memfile.
+# We'll use memfile  because it doesn't require any prior set up.
+  "lease-database": {
+      "type": "memfile",
+      "lfc-interval": 3600
+  },
+
+# Addresses will be assigned with preferred and valid lifetimes
+# being 3000 and 4000, respectively. Client is told to start
+# renewing after 1000 seconds. If the server does not respond
+# after 2000 seconds since the lease was granted, client is supposed
+# to start REBIND procedure (emergency renewal that allows switching
+# to a different server).
+  "preferred-lifetime": 3000,
+  "valid-lifetime": 4000,
+  "renew-timer": 1000,
+  "rebind-timer": 2000,
+
+# The following list defines subnets. Each subnet consists of at
+# least subnet and pool entries.
+  "subnet6": [
+    {
+      "pools": [ { "pool": "2001:db8:1::/80" } ],
+      "subnet": "2001:db8:1::/64",
+      "interface": "ethX"
+    }
+  ],
+
+# Enable dynamic DNS updates
+  "dhcp-ddns" : {
+        "enable-updates" : true,
+        "server-ip" : "3001::1",
+        "server-port" : 3432,
+        "sender-ip" : "3001::2",
+        "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" : "when-present",
+        "generated-prefix" : "test.prefix",
+        "qualifying-suffix" : "test.suffix."
+  }
+
+},
+
+# The following configures logging. It assumes that messages with at least
+# informational level (info, warn, error and fatal) should be logged to stdout.
+"Logging": {
+    "loggers": [
+        {
+            "name": "kea-dhcp6",
+            "output_options": [
+                {
+                    "output": "stdout"
+                }
+            ],
+            "debuglevel": 0,
+            "severity": "INFO"
+        }
+    ]
+}
+
+}
+

+ 4 - 3
doc/guide/dhcp4-srv.xml

@@ -2174,9 +2174,10 @@ It is merely echoed by the server
     <note>
     <note>
     Note that formerly, this parameter was a boolean and permitted only values
     Note that formerly, this parameter was a boolean and permitted only values
     of <command>true</command> and <command>false</command>.  Boolean values
     of <command>true</command> and <command>false</command>.  Boolean values
-    will still be accepted but may eventually be deprecated. A value of
-    <command>true</command> equates to <command>when-present</command>,
-    <command>false</command> equates to <command>never</command>.
+    have been deprecated and are no longer accepted.  If you are currently using
+    booleans, you must replace them with the desired mode name. A value of
+    <command>true</command> maps to <command>"when-present"</command>, while
+    <command>false</command> maps to <command>"never"</command>.
     </note>
     </note>
 
 
       For example, To instruct kea-dhcp4 to always generate the FQDN for a
       For example, To instruct kea-dhcp4 to always generate the FQDN for a

+ 4 - 3
doc/guide/dhcp6-srv.xml

@@ -2372,9 +2372,10 @@ should include options from the isc option space:
     <note>
     <note>
     Note that formerly, this parameter was a boolean and permitted only values
     Note that formerly, this parameter was a boolean and permitted only values
     of <command>true</command> and <command>false</command>.  Boolean values
     of <command>true</command> and <command>false</command>.  Boolean values
-    will still be accepted but may eventually be deprecated. A value of
-    <command>true</command> equates to <command>when-present</command>,
-    <command>false</command> equates to <command>never</command>.
+    have been deprecated and are no longer accepted.  If you are currently using
+    booleans, you must replace them with the desired mode name. A value of
+    <command>true</command> maps to <command>"when-present"</command>, while
+    <command>false</command> maps to <command>"never"</command>.
     </note>
     </note>
 
 
       For example, To instruct kea-dhcp6 to always generate the FQDN for a
       For example, To instruct kea-dhcp6 to always generate the FQDN for a

File diff suppressed because it is too large
+ 1108 - 819
src/bin/dhcp4/dhcp4_lexer.cc


+ 227 - 0
src/bin/dhcp4/dhcp4_lexer.ll

@@ -121,6 +121,8 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DATA(driver.loc_);
             return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DATA(driver.loc_);
         case Parser4Context::PARSER_HOOKS_LIBRARY:
         case Parser4Context::PARSER_HOOKS_LIBRARY:
             return isc::dhcp::Dhcp4Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
             return isc::dhcp::Dhcp4Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
+        case Parser4Context::PARSER_DHCP_DDNS:
+            return isc::dhcp::Dhcp4Parser::make_SUB_DHCP_DDNS(driver.loc_);
         }
         }
     }
     }
 %}
 %}
@@ -887,6 +889,231 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
     }
 }
 }
 
 
+\"enable-updates\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_ENABLE_UPDATES(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("enable-updates", driver.loc_);
+    }
+}
+
+\"qualifying-suffix\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_QUALIFYING_SUFFIX(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("qualifying-suffix", driver.loc_);
+    }
+}
+
+\"server-ip\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_SERVER_IP(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("server-ip", driver.loc_);
+    }
+}
+
+\"server-port\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_SERVER_PORT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("server-port", driver.loc_);
+    }
+}
+
+\"sender-ip\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_SENDER_IP(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("sender-ip", driver.loc_);
+    }
+}
+
+\"sender-port\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_SENDER_PORT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("sender-port", driver.loc_);
+    }
+}
+
+\"max-queue-size\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_MAX_QUEUE_SIZE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("max-queue-size", driver.loc_);
+    }
+}
+
+\"ncr-protocol\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_NCR_PROTOCOL(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("ncr-protocol", driver.loc_);
+    }
+}
+
+\"ncr-format\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_NCR_FORMAT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("ncr-format", driver.loc_);
+    }
+}
+
+\"always-include-fqdn\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_ALWAYS_INCLUDE_FQDN(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("always-include-fqdn", driver.loc_);
+    }
+}
+
+\"allow-client-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_ALLOW_CLIENT_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("allow-client-update", driver.loc_);
+    }
+}
+
+\"override-no-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_OVERRIDE_NO_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("override-no-update", driver.loc_);
+    }
+}
+
+\"override-client-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_OVERRIDE_CLIENT_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("override-client-update", driver.loc_);
+    }
+}
+
+\"replace-client-name\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_REPLACE_CLIENT_NAME(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("replace-client-name", driver.loc_);
+    }
+}
+
+\"generated-prefix\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp4Parser::make_GENERATED_PREFIX(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("generated-prefix", driver.loc_);
+    }
+}
+
+(?i:\"UDP\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_PROTOCOL) {
+        return isc::dhcp::Dhcp4Parser::make_UDP(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"TCP\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_PROTOCOL) {
+        return isc::dhcp::Dhcp4Parser::make_TCP(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"JSON\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::NCR_FORMAT) {
+        return isc::dhcp::Dhcp4Parser::make_JSON(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"when-present\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_WHEN_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"true\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_WHEN_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"never\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_NEVER(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"false\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_NEVER(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"always\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_ALWAYS(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"when-not-present\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser4Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp4Parser::make_WHEN_NOT_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp4Parser::make_STRING(tmp, driver.loc_);
+}
+
 \"Dhcp6\"  {
 \"Dhcp6\"  {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::CONFIG:
     case isc::dhcp::Parser4Context::CONFIG:

File diff suppressed because it is too large
+ 1561 - 1280
src/bin/dhcp4/dhcp4_parser.cc


+ 370 - 197
src/bin/dhcp4/dhcp4_parser.h

@@ -305,7 +305,8 @@ namespace isc { namespace dhcp {
     union union_type
     union union_type
     {
     {
       // value
       // value
-      // socket_type
+      // ncr_protocol_value
+      // replace_client_name_value
       char dummy1[sizeof(ElementPtr)];
       char dummy1[sizeof(ElementPtr)];
 
 
       // "boolean"
       // "boolean"
@@ -353,102 +354,117 @@ namespace isc { namespace dhcp {
         TOKEN_INTERFACES_CONFIG = 266,
         TOKEN_INTERFACES_CONFIG = 266,
         TOKEN_INTERFACES = 267,
         TOKEN_INTERFACES = 267,
         TOKEN_DHCP_SOCKET_TYPE = 268,
         TOKEN_DHCP_SOCKET_TYPE = 268,
-        TOKEN_RAW = 269,
-        TOKEN_UDP = 270,
-        TOKEN_ECHO_CLIENT_ID = 271,
-        TOKEN_MATCH_CLIENT_ID = 272,
-        TOKEN_NEXT_SERVER = 273,
-        TOKEN_SERVER_HOSTNAME = 274,
-        TOKEN_BOOT_FILE_NAME = 275,
-        TOKEN_LEASE_DATABASE = 276,
-        TOKEN_HOSTS_DATABASE = 277,
-        TOKEN_TYPE = 278,
-        TOKEN_USER = 279,
-        TOKEN_PASSWORD = 280,
-        TOKEN_HOST = 281,
-        TOKEN_PERSIST = 282,
-        TOKEN_LFC_INTERVAL = 283,
-        TOKEN_READONLY = 284,
-        TOKEN_VALID_LIFETIME = 285,
-        TOKEN_RENEW_TIMER = 286,
-        TOKEN_REBIND_TIMER = 287,
-        TOKEN_DECLINE_PROBATION_PERIOD = 288,
-        TOKEN_SUBNET4 = 289,
-        TOKEN_SUBNET_4O6_INTERFACE = 290,
-        TOKEN_SUBNET_4O6_INTERFACE_ID = 291,
-        TOKEN_SUBNET_4O6_SUBNET = 292,
-        TOKEN_OPTION_DEF = 293,
-        TOKEN_OPTION_DATA = 294,
-        TOKEN_NAME = 295,
-        TOKEN_DATA = 296,
-        TOKEN_CODE = 297,
-        TOKEN_SPACE = 298,
-        TOKEN_CSV_FORMAT = 299,
-        TOKEN_RECORD_TYPES = 300,
-        TOKEN_ENCAPSULATE = 301,
-        TOKEN_ARRAY = 302,
-        TOKEN_POOLS = 303,
-        TOKEN_POOL = 304,
-        TOKEN_SUBNET = 305,
-        TOKEN_INTERFACE = 306,
-        TOKEN_INTERFACE_ID = 307,
-        TOKEN_ID = 308,
-        TOKEN_RAPID_COMMIT = 309,
-        TOKEN_RESERVATION_MODE = 310,
-        TOKEN_HOST_RESERVATION_IDENTIFIERS = 311,
-        TOKEN_CLIENT_CLASSES = 312,
-        TOKEN_TEST = 313,
-        TOKEN_CLIENT_CLASS = 314,
-        TOKEN_RESERVATIONS = 315,
-        TOKEN_DUID = 316,
-        TOKEN_HW_ADDRESS = 317,
-        TOKEN_CIRCUIT_ID = 318,
-        TOKEN_CLIENT_ID = 319,
-        TOKEN_HOSTNAME = 320,
-        TOKEN_RELAY = 321,
-        TOKEN_IP_ADDRESS = 322,
-        TOKEN_HOOKS_LIBRARIES = 323,
-        TOKEN_LIBRARY = 324,
-        TOKEN_PARAMETERS = 325,
-        TOKEN_EXPIRED_LEASES_PROCESSING = 326,
-        TOKEN_RECLAIM_TIMER_WAIT_TIME = 327,
-        TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 328,
-        TOKEN_HOLD_RECLAIMED_TIME = 329,
-        TOKEN_MAX_RECLAIM_LEASES = 330,
-        TOKEN_MAX_RECLAIM_TIME = 331,
-        TOKEN_UNWARNED_RECLAIM_CYCLES = 332,
-        TOKEN_SERVER_ID = 333,
-        TOKEN_IDENTIFIER = 334,
-        TOKEN_HTYPE = 335,
-        TOKEN_TIME = 336,
-        TOKEN_ENTERPRISE_ID = 337,
-        TOKEN_DHCP4O6_PORT = 338,
-        TOKEN_CONTROL_SOCKET = 339,
-        TOKEN_SOCKET_TYPE = 340,
-        TOKEN_SOCKET_NAME = 341,
-        TOKEN_DHCP_DDNS = 342,
-        TOKEN_LOGGING = 343,
-        TOKEN_LOGGERS = 344,
-        TOKEN_OUTPUT_OPTIONS = 345,
-        TOKEN_OUTPUT = 346,
-        TOKEN_DEBUGLEVEL = 347,
-        TOKEN_SEVERITY = 348,
-        TOKEN_DHCP6 = 349,
-        TOKEN_DHCPDDNS = 350,
-        TOKEN_TOPLEVEL_JSON = 351,
-        TOKEN_TOPLEVEL_DHCP4 = 352,
-        TOKEN_SUB_DHCP4 = 353,
-        TOKEN_SUB_INTERFACES4 = 354,
-        TOKEN_SUB_SUBNET4 = 355,
-        TOKEN_SUB_POOL4 = 356,
-        TOKEN_SUB_RESERVATION = 357,
-        TOKEN_SUB_OPTION_DEF = 358,
-        TOKEN_SUB_OPTION_DATA = 359,
-        TOKEN_SUB_HOOKS_LIBRARY = 360,
-        TOKEN_STRING = 361,
-        TOKEN_INTEGER = 362,
-        TOKEN_FLOAT = 363,
-        TOKEN_BOOLEAN = 364
+        TOKEN_ECHO_CLIENT_ID = 269,
+        TOKEN_MATCH_CLIENT_ID = 270,
+        TOKEN_NEXT_SERVER = 271,
+        TOKEN_SERVER_HOSTNAME = 272,
+        TOKEN_BOOT_FILE_NAME = 273,
+        TOKEN_LEASE_DATABASE = 274,
+        TOKEN_HOSTS_DATABASE = 275,
+        TOKEN_TYPE = 276,
+        TOKEN_USER = 277,
+        TOKEN_PASSWORD = 278,
+        TOKEN_HOST = 279,
+        TOKEN_PERSIST = 280,
+        TOKEN_LFC_INTERVAL = 281,
+        TOKEN_READONLY = 282,
+        TOKEN_VALID_LIFETIME = 283,
+        TOKEN_RENEW_TIMER = 284,
+        TOKEN_REBIND_TIMER = 285,
+        TOKEN_DECLINE_PROBATION_PERIOD = 286,
+        TOKEN_SUBNET4 = 287,
+        TOKEN_SUBNET_4O6_INTERFACE = 288,
+        TOKEN_SUBNET_4O6_INTERFACE_ID = 289,
+        TOKEN_SUBNET_4O6_SUBNET = 290,
+        TOKEN_OPTION_DEF = 291,
+        TOKEN_OPTION_DATA = 292,
+        TOKEN_NAME = 293,
+        TOKEN_DATA = 294,
+        TOKEN_CODE = 295,
+        TOKEN_SPACE = 296,
+        TOKEN_CSV_FORMAT = 297,
+        TOKEN_RECORD_TYPES = 298,
+        TOKEN_ENCAPSULATE = 299,
+        TOKEN_ARRAY = 300,
+        TOKEN_POOLS = 301,
+        TOKEN_POOL = 302,
+        TOKEN_SUBNET = 303,
+        TOKEN_INTERFACE = 304,
+        TOKEN_INTERFACE_ID = 305,
+        TOKEN_ID = 306,
+        TOKEN_RAPID_COMMIT = 307,
+        TOKEN_RESERVATION_MODE = 308,
+        TOKEN_HOST_RESERVATION_IDENTIFIERS = 309,
+        TOKEN_CLIENT_CLASSES = 310,
+        TOKEN_TEST = 311,
+        TOKEN_CLIENT_CLASS = 312,
+        TOKEN_RESERVATIONS = 313,
+        TOKEN_DUID = 314,
+        TOKEN_HW_ADDRESS = 315,
+        TOKEN_CIRCUIT_ID = 316,
+        TOKEN_CLIENT_ID = 317,
+        TOKEN_HOSTNAME = 318,
+        TOKEN_RELAY = 319,
+        TOKEN_IP_ADDRESS = 320,
+        TOKEN_HOOKS_LIBRARIES = 321,
+        TOKEN_LIBRARY = 322,
+        TOKEN_PARAMETERS = 323,
+        TOKEN_EXPIRED_LEASES_PROCESSING = 324,
+        TOKEN_SERVER_ID = 325,
+        TOKEN_IDENTIFIER = 326,
+        TOKEN_HTYPE = 327,
+        TOKEN_TIME = 328,
+        TOKEN_ENTERPRISE_ID = 329,
+        TOKEN_DHCP4O6_PORT = 330,
+        TOKEN_CONTROL_SOCKET = 331,
+        TOKEN_SOCKET_TYPE = 332,
+        TOKEN_SOCKET_NAME = 333,
+        TOKEN_DHCP_DDNS = 334,
+        TOKEN_ENABLE_UPDATES = 335,
+        TOKEN_QUALIFYING_SUFFIX = 336,
+        TOKEN_SERVER_IP = 337,
+        TOKEN_SERVER_PORT = 338,
+        TOKEN_SENDER_IP = 339,
+        TOKEN_SENDER_PORT = 340,
+        TOKEN_MAX_QUEUE_SIZE = 341,
+        TOKEN_NCR_PROTOCOL = 342,
+        TOKEN_NCR_FORMAT = 343,
+        TOKEN_ALWAYS_INCLUDE_FQDN = 344,
+        TOKEN_ALLOW_CLIENT_UPDATE = 345,
+        TOKEN_OVERRIDE_NO_UPDATE = 346,
+        TOKEN_OVERRIDE_CLIENT_UPDATE = 347,
+        TOKEN_REPLACE_CLIENT_NAME = 348,
+        TOKEN_GENERATED_PREFIX = 349,
+        TOKEN_UDP = 350,
+        TOKEN_TCP = 351,
+        TOKEN_JSON = 352,
+        TOKEN_WHEN_PRESENT = 353,
+        TOKEN_NEVER = 354,
+        TOKEN_ALWAYS = 355,
+        TOKEN_WHEN_NOT_PRESENT = 356,
+        TOKEN_LOGGING = 357,
+        TOKEN_LOGGERS = 358,
+        TOKEN_OUTPUT_OPTIONS = 359,
+        TOKEN_OUTPUT = 360,
+        TOKEN_DEBUGLEVEL = 361,
+        TOKEN_SEVERITY = 362,
+        TOKEN_DHCP6 = 363,
+        TOKEN_DHCPDDNS = 364,
+        TOKEN_TOPLEVEL_JSON = 365,
+        TOKEN_TOPLEVEL_DHCP4 = 366,
+        TOKEN_SUB_DHCP4 = 367,
+        TOKEN_SUB_INTERFACES4 = 368,
+        TOKEN_SUB_SUBNET4 = 369,
+        TOKEN_SUB_POOL4 = 370,
+        TOKEN_SUB_RESERVATION = 371,
+        TOKEN_SUB_OPTION_DEF = 372,
+        TOKEN_SUB_OPTION_DATA = 373,
+        TOKEN_SUB_HOOKS_LIBRARY = 374,
+        TOKEN_SUB_DHCP_DDNS = 375,
+        TOKEN_STRING = 376,
+        TOKEN_INTEGER = 377,
+        TOKEN_FLOAT = 378,
+        TOKEN_BOOLEAN = 379
       };
       };
     };
     };
 
 
@@ -613,14 +629,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_RAW (const location_type& l);
-
-    static inline
-    symbol_type
-    make_UDP (const location_type& l);
-
-    static inline
-    symbol_type
     make_ECHO_CLIENT_ID (const location_type& l);
     make_ECHO_CLIENT_ID (const location_type& l);
 
 
     static inline
     static inline
@@ -845,67 +853,131 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_RECLAIM_TIMER_WAIT_TIME (const location_type& l);
+    make_SERVER_ID (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_FLUSH_RECLAIMED_TIMER_WAIT_TIME (const location_type& l);
+    make_IDENTIFIER (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_HOLD_RECLAIMED_TIME (const location_type& l);
+    make_HTYPE (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MAX_RECLAIM_LEASES (const location_type& l);
+    make_TIME (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MAX_RECLAIM_TIME (const location_type& l);
+    make_ENTERPRISE_ID (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_UNWARNED_RECLAIM_CYCLES (const location_type& l);
+    make_DHCP4O6_PORT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SERVER_ID (const location_type& l);
+    make_CONTROL_SOCKET (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_IDENTIFIER (const location_type& l);
+    make_SOCKET_TYPE (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_HTYPE (const location_type& l);
+    make_SOCKET_NAME (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_TIME (const location_type& l);
+    make_DHCP_DDNS (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_ENTERPRISE_ID (const location_type& l);
+    make_ENABLE_UPDATES (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_DHCP4O6_PORT (const location_type& l);
+    make_QUALIFYING_SUFFIX (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_CONTROL_SOCKET (const location_type& l);
+    make_SERVER_IP (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SOCKET_TYPE (const location_type& l);
+    make_SERVER_PORT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SOCKET_NAME (const location_type& l);
+    make_SENDER_IP (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_DHCP_DDNS (const location_type& l);
+    make_SENDER_PORT (const location_type& l);
+
+    static inline
+    symbol_type
+    make_MAX_QUEUE_SIZE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_NCR_PROTOCOL (const location_type& l);
+
+    static inline
+    symbol_type
+    make_NCR_FORMAT (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALWAYS_INCLUDE_FQDN (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALLOW_CLIENT_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_OVERRIDE_NO_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_OVERRIDE_CLIENT_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_REPLACE_CLIENT_NAME (const location_type& l);
+
+    static inline
+    symbol_type
+    make_GENERATED_PREFIX (const location_type& l);
+
+    static inline
+    symbol_type
+    make_UDP (const location_type& l);
+
+    static inline
+    symbol_type
+    make_TCP (const location_type& l);
+
+    static inline
+    symbol_type
+    make_JSON (const location_type& l);
+
+    static inline
+    symbol_type
+    make_WHEN_PRESENT (const location_type& l);
+
+    static inline
+    symbol_type
+    make_NEVER (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALWAYS (const location_type& l);
+
+    static inline
+    symbol_type
+    make_WHEN_NOT_PRESENT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
@@ -981,6 +1053,10 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
+    make_SUB_DHCP_DDNS (const location_type& l);
+
+    static inline
+    symbol_type
     make_STRING (const std::string& v, const location_type& l);
     make_STRING (const std::string& v, const location_type& l);
 
 
     static inline
     static inline
@@ -1200,12 +1276,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 647,     ///< Last index in yytable_.
-      yynnts_ = 274,  ///< Number of nonterminal symbols.
-      yyfinal_ = 22, ///< Termination state number.
+      yylast_ = 705,     ///< Last index in yytable_.
+      yynnts_ = 296,  ///< Number of nonterminal symbols.
+      yyfinal_ = 24, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 110  ///< Number of tokens.
+      yyntokens_ = 125  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1258,9 +1334,10 @@ namespace isc { namespace dhcp {
       75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
       75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
       85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
       85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
-     105,   106,   107,   108,   109
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124
     };
     };
-    const unsigned int user_token_number_max_ = 364;
+    const unsigned int user_token_number_max_ = 379;
     const token_number_type undef_token_ = 2;
     const token_number_type undef_token_ = 2;
 
 
     if (static_cast<int>(t) <= yyeof_)
     if (static_cast<int>(t) <= yyeof_)
@@ -1293,24 +1370,25 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 122: // value
-      case 161: // socket_type
+      case 138: // value
+      case 383: // ncr_protocol_value
+      case 392: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 109: // "boolean"
+      case 124: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 108: // "floating point"
+      case 123: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 107: // "integer"
+      case 122: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 106: // "constant string"
+      case 121: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1331,24 +1409,25 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 122: // value
-      case 161: // socket_type
+      case 138: // value
+      case 383: // ncr_protocol_value
+      case 392: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 109: // "boolean"
+      case 124: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 108: // "floating point"
+      case 123: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 107: // "integer"
+      case 122: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 106: // "constant string"
+      case 121: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1428,24 +1507,25 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 122: // value
-      case 161: // socket_type
+      case 138: // value
+      case 383: // ncr_protocol_value
+      case 392: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 109: // "boolean"
+      case 124: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 108: // "floating point"
+      case 123: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 107: // "integer"
+      case 122: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 106: // "constant string"
+      case 121: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1472,24 +1552,25 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 122: // value
-      case 161: // socket_type
+      case 138: // value
+      case 383: // ncr_protocol_value
+      case 392: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 109: // "boolean"
+      case 124: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 108: // "floating point"
+      case 123: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 107: // "integer"
+      case 122: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 106: // "constant string"
+      case 121: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1558,7 +1639,9 @@ namespace isc { namespace dhcp {
      325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
      325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
      335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
      335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
      345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
      345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
-     355,   356,   357,   358,   359,   360,   361,   362,   363,   364
+     355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
+     365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
+     375,   376,   377,   378,   379
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -1636,18 +1719,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_RAW (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_RAW, l);
-  }
-
-  Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_UDP (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_UDP, l);
-  }
-
-  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_ECHO_CLIENT_ID (const location_type& l)
   Dhcp4Parser::make_ECHO_CLIENT_ID (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_ECHO_CLIENT_ID, l);
     return symbol_type (token::TOKEN_ECHO_CLIENT_ID, l);
@@ -1984,99 +2055,195 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_RECLAIM_TIMER_WAIT_TIME (const location_type& l)
+  Dhcp4Parser::make_SERVER_ID (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_RECLAIM_TIMER_WAIT_TIME, l);
+    return symbol_type (token::TOKEN_SERVER_ID, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_FLUSH_RECLAIMED_TIMER_WAIT_TIME (const location_type& l)
+  Dhcp4Parser::make_IDENTIFIER (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME, l);
+    return symbol_type (token::TOKEN_IDENTIFIER, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_HOLD_RECLAIMED_TIME (const location_type& l)
+  Dhcp4Parser::make_HTYPE (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_HOLD_RECLAIMED_TIME, l);
+    return symbol_type (token::TOKEN_HTYPE, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_MAX_RECLAIM_LEASES (const location_type& l)
+  Dhcp4Parser::make_TIME (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_MAX_RECLAIM_LEASES, l);
+    return symbol_type (token::TOKEN_TIME, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_MAX_RECLAIM_TIME (const location_type& l)
+  Dhcp4Parser::make_ENTERPRISE_ID (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_MAX_RECLAIM_TIME, l);
+    return symbol_type (token::TOKEN_ENTERPRISE_ID, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_UNWARNED_RECLAIM_CYCLES (const location_type& l)
+  Dhcp4Parser::make_DHCP4O6_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_UNWARNED_RECLAIM_CYCLES, l);
+    return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_SERVER_ID (const location_type& l)
+  Dhcp4Parser::make_CONTROL_SOCKET (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SERVER_ID, l);
+    return symbol_type (token::TOKEN_CONTROL_SOCKET, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_IDENTIFIER (const location_type& l)
+  Dhcp4Parser::make_SOCKET_TYPE (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_IDENTIFIER, l);
+    return symbol_type (token::TOKEN_SOCKET_TYPE, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_HTYPE (const location_type& l)
+  Dhcp4Parser::make_SOCKET_NAME (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_HTYPE, l);
+    return symbol_type (token::TOKEN_SOCKET_NAME, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_TIME (const location_type& l)
+  Dhcp4Parser::make_DHCP_DDNS (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_TIME, l);
+    return symbol_type (token::TOKEN_DHCP_DDNS, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_ENTERPRISE_ID (const location_type& l)
+  Dhcp4Parser::make_ENABLE_UPDATES (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_ENTERPRISE_ID, l);
+    return symbol_type (token::TOKEN_ENABLE_UPDATES, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_DHCP4O6_PORT (const location_type& l)
+  Dhcp4Parser::make_QUALIFYING_SUFFIX (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
+    return symbol_type (token::TOKEN_QUALIFYING_SUFFIX, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_CONTROL_SOCKET (const location_type& l)
+  Dhcp4Parser::make_SERVER_IP (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_CONTROL_SOCKET, l);
+    return symbol_type (token::TOKEN_SERVER_IP, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_SOCKET_TYPE (const location_type& l)
+  Dhcp4Parser::make_SERVER_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SOCKET_TYPE, l);
+    return symbol_type (token::TOKEN_SERVER_PORT, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_SOCKET_NAME (const location_type& l)
+  Dhcp4Parser::make_SENDER_IP (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SOCKET_NAME, l);
+    return symbol_type (token::TOKEN_SENDER_IP, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_DHCP_DDNS (const location_type& l)
+  Dhcp4Parser::make_SENDER_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_DHCP_DDNS, l);
+    return symbol_type (token::TOKEN_SENDER_PORT, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_MAX_QUEUE_SIZE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_MAX_QUEUE_SIZE, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_NCR_PROTOCOL (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_NCR_PROTOCOL, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_NCR_FORMAT (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_NCR_FORMAT, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_ALWAYS_INCLUDE_FQDN (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALWAYS_INCLUDE_FQDN, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_ALLOW_CLIENT_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALLOW_CLIENT_UPDATE, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_OVERRIDE_CLIENT_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_OVERRIDE_CLIENT_UPDATE, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_REPLACE_CLIENT_NAME (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_REPLACE_CLIENT_NAME, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_GENERATED_PREFIX (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_GENERATED_PREFIX, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_UDP (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_UDP, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_TCP (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_TCP, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_JSON (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_JSON, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_WHEN_PRESENT (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_WHEN_PRESENT, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_NEVER (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_NEVER, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_ALWAYS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALWAYS, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_WHEN_NOT_PRESENT (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_WHEN_NOT_PRESENT, l);
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
@@ -2188,6 +2355,12 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_SUB_DHCP_DDNS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SUB_DHCP_DDNS, l);
+  }
+
+  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_STRING (const std::string& v, const location_type& l)
   Dhcp4Parser::make_STRING (const std::string& v, const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_STRING, v, l);
     return symbol_type (token::TOKEN_STRING, v, l);
@@ -2214,7 +2387,7 @@ namespace isc { namespace dhcp {
 
 
 #line 14 "dhcp4_parser.yy" // lalr1.cc:377
 #line 14 "dhcp4_parser.yy" // lalr1.cc:377
 } } // isc::dhcp
 } } // isc::dhcp
-#line 2218 "dhcp4_parser.h" // lalr1.cc:377
+#line 2391 "dhcp4_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 176 - 22
src/bin/dhcp4/dhcp4_parser.yy

@@ -142,26 +142,28 @@ using namespace std;
   SOCKET_NAME "socket-name"
   SOCKET_NAME "socket-name"
 
 
   DHCP_DDNS "dhcp-ddns"
   DHCP_DDNS "dhcp-ddns"
-
- /// @todo: Implement proper parsing for those parameters in Dhcp4/dhcp-ddns/*.
- /// This should be part of the #5043 ticket. Listing the keywords here for
- /// completeness.
-
- // These are tokens defined in Dhcp4/dhcp-ddns/*
- // They're not
- //  ENABLE_UPDATES "enable-updates"
- //  SERVER_IP "server-ip"
- //  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"
- //  OVERRDIDE_NO_UPDATE "override-no-update"
- //  OVERRDIDE_CLIENT_UPDATE "override-client-update"
- //  REPLACE_CLIENT_NAME "replace-client-name"
- //  GENERATED_PREFIX "generated-prefix"
- //  QUALIFYING_SUFFIX "qualifying-suffix"
+  ENABLE_UPDATES "enable-updates"
+  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"
+  ALLOW_CLIENT_UPDATE "allow-client-update"
+  OVERRIDE_NO_UPDATE "override-no-update"
+  OVERRIDE_CLIENT_UPDATE "override-client-update"
+  REPLACE_CLIENT_NAME "replace-client-name"
+  GENERATED_PREFIX "generated-prefix"
+  UDP "UDP"
+  TCP "TCP"
+  JSON "JSON"
+  WHEN_PRESENT "when-present"
+  NEVER "never"
+  ALWAYS "always"
+  WHEN_NOT_PRESENT "when-not-present"
 
 
   LOGGING "Logging"
   LOGGING "Logging"
   LOGGERS "loggers"
   LOGGERS "loggers"
@@ -185,6 +187,7 @@ using namespace std;
   SUB_OPTION_DEF
   SUB_OPTION_DEF
   SUB_OPTION_DATA
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_HOOKS_LIBRARY
+  SUB_DHCP_DDNS
 ;
 ;
 
 
 %token <std::string> STRING "constant string"
 %token <std::string> STRING "constant string"
@@ -194,6 +197,8 @@ using namespace std;
 
 
 %type <ElementPtr> value
 %type <ElementPtr> value
 %type <ElementPtr> socket_type
 %type <ElementPtr> socket_type
+%type <ElementPtr> ncr_protocol_value
+%type <ElementPtr> replace_client_name_value
 
 
 %printer { yyoutput << $$; } <*>;
 %printer { yyoutput << $$; } <*>;
 
 
@@ -214,6 +219,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
+     | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
      ;
      ;
 
 
 // ---- generic JSON parser ---------------------------------
 // ---- generic JSON parser ---------------------------------
@@ -1431,12 +1437,160 @@ dhcp_ddns: DHCP_DDNS {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
-    ctx.enter(ctx.NO_KEYWORD);
-} COLON LCURLY_BRACKET not_empty_map RCURLY_BRACKET {
+    ctx.enter(ctx.DHCP_DDNS);
+} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+sub_dhcp_ddns: LCURLY_BRACKET {
+    // Parse the dhcp-ddns map
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} dhcp_ddns_params RCURLY_BRACKET {
+    // parsing completed
+};
+
+dhcp_ddns_params: dhcp_ddns_param
+                | dhcp_ddns_params COMMA dhcp_ddns_param
+                ;
+
+dhcp_ddns_param: enable_updates
+               | qualifying_suffix
+               | server_ip
+               | server_port
+               | sender_ip
+               | sender_port
+               | max_queue_size
+               | ncr_protocol
+               | ncr_format
+               | always_include_fqdn
+               | allow_client_update
+               | override_no_update
+               | override_client_update
+               | replace_client_name
+               | generated_prefix
+               | unknown_map_entry
+               ;
+
+enable_updates: ENABLE_UPDATES COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("enable-updates", b);
+};
+
+qualifying_suffix: QUALIFYING_SUFFIX {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("qualifying-suffix", s);
+    ctx.leave();
+};
+
+server_ip: SERVER_IP {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("server-ip", s);
+    ctx.leave();
+};
+
+server_port: SERVER_PORT COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("server-port", i);
+};
+
+sender_ip: SENDER_IP {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("sender-ip", s);
+    ctx.leave();
+};
+
+sender_port: SENDER_PORT COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("sender-port", i);
+};
+
+max_queue_size: MAX_QUEUE_SIZE COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("max-queue-size", i);
+};
+
+ncr_protocol: NCR_PROTOCOL {
+    ctx.enter(ctx.NCR_PROTOCOL);
+} COLON ncr_protocol_value {
+    ctx.stack_.back()->set("ncr-protocol", $4);
+    ctx.leave();
+};
+
+ncr_protocol_value:
+    UDP { $$ = ElementPtr(new StringElement("UDP", ctx.loc2pos(@1))); }
+  | TCP { $$ = ElementPtr(new StringElement("TCP", ctx.loc2pos(@1))); }
+  ;
+
+ncr_format: NCR_FORMAT {
+    ctx.enter(ctx.NCR_FORMAT);
+} COLON JSON {
+    ElementPtr json(new StringElement("JSON", ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("ncr-format", json);
+    ctx.leave();
+};
+
+always_include_fqdn: ALWAYS_INCLUDE_FQDN COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("always-include-fqdn", b);
+};
+
+allow_client_update: ALLOW_CLIENT_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("allow-client-update",  b);
+};
+
+override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("override-no-update", b);
+};
+
+override_client_update: OVERRIDE_CLIENT_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("override-client-update", b);
+};
+
+replace_client_name: REPLACE_CLIENT_NAME {
+    ctx.enter(ctx.REPLACE_CLIENT_NAME);
+} COLON replace_client_name_value {
+    ctx.stack_.back()->set("replace-client-name", $4);
+    ctx.leave();
+};
+
+replace_client_name_value:
+    WHEN_PRESENT {
+      $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); 
+      }
+  | NEVER {
+      $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1)));
+      }
+  | ALWAYS {
+      $$ = ElementPtr(new StringElement("always", ctx.loc2pos(@1)));
+      }
+  | WHEN_NOT_PRESENT {
+      $$ = ElementPtr(new StringElement("when-not-present", ctx.loc2pos(@1)));
+      }
+  | BOOLEAN  {
+      error(@1, "boolean values for the replace-client-name are "
+                "no longer supported");
+      }
+  ;
+
+generated_prefix: GENERATED_PREFIX {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("generated-prefix", s);
+    ctx.leave();
+};
+
 // JSON entries for Dhcp4 and DhcpDdns
 // JSON entries for Dhcp4 and DhcpDdns
 
 
 dhcp6_json_object: DHCP6 {
 dhcp6_json_object: DHCP6 {

+ 17 - 2
src/bin/dhcp4/json_config_parser.cc

@@ -432,8 +432,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
         // hooks-libraries are now migrated to SimpleParser.
         // hooks-libraries are now migrated to SimpleParser.
     } else if (config_id.compare("echo-client-id") == 0) {
     } else if (config_id.compare("echo-client-id") == 0) {
         parser = new BooleanParser(config_id, globalContext()->boolean_values_);
         parser = new BooleanParser(config_id, globalContext()->boolean_values_);
-    } else if (config_id.compare("dhcp-ddns") == 0) {
-        parser = new D2ClientConfigParser(config_id);
+    // dhcp-ddns has been converted to SimpleParser.
     } else if (config_id.compare("match-client-id") == 0) {
     } else if (config_id.compare("match-client-id") == 0) {
         parser = new BooleanParser(config_id, globalContext()->boolean_values_);
         parser = new BooleanParser(config_id, globalContext()->boolean_values_);
     // control-socket has been converted to SimpleParser already.
     // control-socket has been converted to SimpleParser already.
@@ -667,6 +666,17 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
             }
             }
             
             
             // Legacy DhcpConfigParser stuff below
             // Legacy DhcpConfigParser stuff below
+            if (config_pair.first == "dhcp-ddns") {
+                // Apply defaults if not in short cut
+                if (!D2ClientConfigParser::isShortCutDisabled(config_pair.second)) {
+                    D2ClientConfigParser::setAllDefaults(config_pair.second);
+                }
+                D2ClientConfigParser parser;
+                D2ClientConfigPtr cfg = parser.parse(config_pair.second);
+                CfgMgr::instance().getStagingCfg()->setD2ClientConfig(cfg);
+                continue;
+            }
+
             ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
             ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
                                                            config_pair.second));
                                                            config_pair.second));
             LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
             LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
@@ -752,6 +762,11 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
             // revert it.  As a result, the failure to commit a subsequent
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
             // change causes problems when trying to roll back.
             hooks_parser.loadLibraries();
             hooks_parser.loadLibraries();
+
+            // Apply the staged D2ClientConfig, used to be done by parser commit
+            D2ClientConfigPtr cfg;
+            cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
+            CfgMgr::instance().setD2ClientConfig(cfg);
         }
         }
         catch (const isc::Exception& ex) {
         catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());

+ 8 - 0
src/bin/dhcp4/parser_context.cc

@@ -163,6 +163,14 @@ Parser4Context::contextName()
         return ("loggers");
         return ("loggers");
     case OUTPUT_OPTIONS:
     case OUTPUT_OPTIONS:
         return ("output-options");
         return ("output-options");
+    case DHCP_DDNS:
+        return ("dhcp-ddns");
+    case NCR_PROTOCOL:
+        return ("ncr-protocol");
+    case NCR_FORMAT:
+        return ("ncr-format");
+    case REPLACE_CLIENT_NAME:
+        return ("replace-client-name");
     default:
     default:
         return ("__unknown__");
         return ("__unknown__");
     }
     }

+ 19 - 4
src/bin/dhcp4/parser_context.h

@@ -80,7 +80,10 @@ public:
         PARSER_OPTION_DATA,
         PARSER_OPTION_DATA,
 
 
         /// This will parse the input as hooks-library.
         /// This will parse the input as hooks-library.
-        PARSER_HOOKS_LIBRARY
+        PARSER_HOOKS_LIBRARY,
+
+        /// This will parse the input as dhcp-ddns.
+        PARSER_DHCP_DDNS
     } ParserType;
     } ParserType;
 
 
     /// @brief Default constructor.
     /// @brief Default constructor.
@@ -184,8 +187,7 @@ public:
         ///< Used while parsing content of Dhcp4.
         ///< Used while parsing content of Dhcp4.
         DHCP4,
         DHCP4,
 
 
-        // not yet DHCP6,
-        // not yet DHCP_DDNS,
+        // not yet Dhcp6, DhcpDdns,
 
 
         ///< Used while parsing content of Logging
         ///< Used while parsing content of Logging
         LOGGING,
         LOGGING,
@@ -247,7 +249,20 @@ public:
         LOGGERS,
         LOGGERS,
 
 
         /// Used while parsing Logging/loggers/output_options structures.
         /// Used while parsing Logging/loggers/output_options structures.
-        OUTPUT_OPTIONS
+        OUTPUT_OPTIONS,
+
+        /// Used while parsing Dhcp4/dhcp-ddns.
+        DHCP_DDNS,
+
+        /// Used while parsing Dhcp4/dhcp-ddns/ncr-protocol
+        NCR_PROTOCOL,
+
+        /// Used while parsing Dhcp4/dhcp-ddns/ncr-format
+        NCR_FORMAT,
+
+        /// Used while parsing Dhcp4/dhcp-ddns/replace-client-name.
+        REPLACE_CLIENT_NAME
+
     } ParserContext;
     } ParserContext;
 
 
     /// @brief File name
     /// @brief File name

+ 1 - 1
src/bin/dhcp4/position.hh

@@ -1,4 +1,4 @@
-// Generated 201701102225
+// Generated 201701131911
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Positions for Bison parsers in C++
 // Positions for Bison parsers in C++

+ 1 - 1
src/bin/dhcp4/stack.hh

@@ -1,4 +1,4 @@
-// Generated 201701102225
+// Generated 201701131911
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Stack handling for Bison parsers in C++
 // Stack handling for Bison parsers in C++

+ 1 - 1
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -3301,7 +3301,7 @@ TEST_F(Dhcp4ParserTest, d2ClientConfig) {
 
 
     // Convert the JSON string to configuration elements.
     // Convert the JSON string to configuration elements.
     ConstElementPtr config;
     ConstElementPtr config;
-    ASSERT_NO_THROW(config = parseDHCP4(config_str));
+    ASSERT_NO_THROW(config = parseDHCP4(config_str, true));
 
 
     // Pass the configuration in for parsing.
     // Pass the configuration in for parsing.
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));

+ 2 - 2
src/bin/dhcp4/tests/d2_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -112,7 +112,7 @@ Dhcp4SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "     \"allow-client-update\" : true, "
         "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
-        "     \"replace-client-name\" : true, "
+        "     \"replace-client-name\" : \"when-present\", "
         "     \"generated-prefix\" : \"test.prefix\", "
         "     \"generated-prefix\" : \"test.prefix\", "
         "     \"qualifying-suffix\" : \"test.suffix.\" },"
         "     \"qualifying-suffix\" : \"test.suffix.\" },"
         "\"valid-lifetime\": 4000 }";
         "\"valid-lifetime\": 4000 }";

+ 11 - 28
src/bin/dhcp4/tests/fqdn_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -427,10 +427,7 @@ public:
     // in a client request correctly, according to the replace-client-name
     // in a client request correctly, according to the replace-client-name
     // mode configuration parameter.
     // mode configuration parameter.
     //
     //
-    // @param mode - value to use client-name-replacment parameter - for
-    // mode labels such as NEVER and ALWAYS must incluce enclosing quotes:
-    // "\"NEVER\"".  This allows us to also pass in boolean literals which
-    // are unquoted.
+    // @param mode - value to use for replace-client-name
     // @param client_name_flag - specifies whether or not the client request
     // @param client_name_flag - specifies whether or not the client request
     // should contain a hostname option
     // should contain a hostname option
     // @param exp_replacement_flag - specifies whether or not the server is
     // @param exp_replacement_flag - specifies whether or not the server is
@@ -452,7 +449,7 @@ public:
             "\"dhcp-ddns\": {"
             "\"dhcp-ddns\": {"
             "\"enable-updates\": true,"
             "\"enable-updates\": true,"
             "\"qualifying-suffix\": \"fake-suffix.isc.org.\","
             "\"qualifying-suffix\": \"fake-suffix.isc.org.\","
-            "\"replace-client-name\": %s"
+            "\"replace-client-name\": \"%s\""
             "}}";
             "}}";
 
 
         // Create the configuration and configure the server
         // Create the configuration and configure the server
@@ -1551,39 +1548,25 @@ TEST_F(NameDhcpv4SrvTest, emptyFqdn) {
 // the supported modes.
 // the supported modes.
 TEST_F(NameDhcpv4SrvTest, replaceClientNameModeTest) {
 TEST_F(NameDhcpv4SrvTest, replaceClientNameModeTest) {
 
 
-    // We pass mode labels in with enclosing quotes so we can also test
-    // unquoted boolean literals true/false
-    testReplaceClientNameMode("\"never\"",
+    testReplaceClientNameMode("never",
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("\"never\"",
+    testReplaceClientNameMode("never",
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
 
 
-    testReplaceClientNameMode("\"always\"",
+    testReplaceClientNameMode("always",
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
-    testReplaceClientNameMode("\"always\"",
+    testReplaceClientNameMode("always",
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
 
 
-    testReplaceClientNameMode("\"when-present\"",
+    testReplaceClientNameMode("when-present",
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("\"when-present\"",
+    testReplaceClientNameMode("when-present",
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
 
 
-    testReplaceClientNameMode("\"when-not-present\"",
+    testReplaceClientNameMode("when-not-present",
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
-    testReplaceClientNameMode("\"when-not-present\"",
+    testReplaceClientNameMode("when-not-present",
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
-
-    // Verify that boolean false produces the same result as RCM_NEVER
-    testReplaceClientNameMode("false",
-                              CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("false",
-                              CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
-
-    // Verify that boolean true produces the same result as RCM_WHEN_PRESENT
-    testReplaceClientNameMode("true",
-                              CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("true",
-                              CLIENT_NAME_PRESENT, NAME_REPLACED);
 }
 }
 
 
 } // end of anonymous namespace
 } // end of anonymous namespace

+ 2 - 1
src/bin/dhcp4/tests/parser_unittest.cc

@@ -250,7 +250,8 @@ TEST(ParserTest, file) {
                                "pgsql-reservations.json",
                                "pgsql-reservations.json",
                                "reservations.json",
                                "reservations.json",
                                "several-subnets.json",
                                "several-subnets.json",
-                               "single-subnet.json" };
+                               "single-subnet.json",
+                               "with-ddns.json" };
 
 
     for (int i = 0; i<configs.size(); i++) {
     for (int i = 0; i<configs.size(); i++) {
         testFile(string(CFG_EXAMPLES) + "/" + configs[i]);
         testFile(string(CFG_EXAMPLES) + "/" + configs[i]);

File diff suppressed because it is too large
+ 1133 - 853
src/bin/dhcp6/dhcp6_lexer.cc


+ 227 - 0
src/bin/dhcp6/dhcp6_lexer.ll

@@ -123,6 +123,8 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
             return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
         case Parser6Context::PARSER_HOOKS_LIBRARY:
         case Parser6Context::PARSER_HOOKS_LIBRARY:
             return isc::dhcp::Dhcp6Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
             return isc::dhcp::Dhcp6Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
+        case Parser6Context::PARSER_DHCP_DDNS:
+            return isc::dhcp::Dhcp6Parser::make_SUB_DHCP_DDNS(driver.loc_);
         }
         }
     }
     }
 %}
 %}
@@ -171,6 +173,231 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
 }
 }
 
 
 
 
+\"enable-updates\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("enable-updates", driver.loc_);
+    }
+}
+
+\"qualifying-suffix\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("qualifying-suffix", driver.loc_);
+    }
+}
+
+\"server-ip\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_SERVER_IP(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("server-ip", driver.loc_);
+    }
+}
+
+\"server-port\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_SERVER_PORT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("server-port", driver.loc_);
+    }
+}
+
+\"sender-ip\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_SENDER_IP(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("sender-ip", driver.loc_);
+    }
+}
+
+\"sender-port\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_SENDER_PORT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("sender-port", driver.loc_);
+    }
+}
+
+\"max-queue-size\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_MAX_QUEUE_SIZE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("max-queue-size", driver.loc_);
+    }
+}
+
+\"ncr-protocol\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_NCR_PROTOCOL(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("ncr-protocol", driver.loc_);
+    }
+}
+
+\"ncr-format\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_NCR_FORMAT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("ncr-format", driver.loc_);
+    }
+}
+
+\"always-include-fqdn\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_ALWAYS_INCLUDE_FQDN(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("always-include-fqdn", driver.loc_);
+    }
+}
+
+\"allow-client-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_ALLOW_CLIENT_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("allow-client-update", driver.loc_);
+    }
+}
+
+\"override-no-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_OVERRIDE_NO_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("override-no-update", driver.loc_);
+    }
+}
+
+\"override-client-update\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_OVERRIDE_CLIENT_UPDATE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("override-client-update", driver.loc_);
+    }
+}
+
+\"replace-client-name\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_REPLACE_CLIENT_NAME(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("replace-client-name", driver.loc_);
+    }
+}
+
+\"generated-prefix\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP_DDNS:
+        return isc::dhcp::Dhcp6Parser::make_GENERATED_PREFIX(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("generated-prefix", driver.loc_);
+    }
+}
+
+(?i:\"UDP\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::NCR_PROTOCOL) {
+        return isc::dhcp::Dhcp6Parser::make_UDP(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"TCP\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::NCR_PROTOCOL) {
+        return isc::dhcp::Dhcp6Parser::make_TCP(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"JSON\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::NCR_FORMAT) {
+        return isc::dhcp::Dhcp6Parser::make_JSON(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"when-present\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_WHEN_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"true\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_WHEN_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"never\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_NEVER(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"false\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_NEVER(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"always\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_ALWAYS(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
+(?i:\"when-not-present\") {
+    /* dhcp-ddns value keywords are case insensitive */
+    if (driver.ctx_ == isc::dhcp::Parser6Context::REPLACE_CLIENT_NAME) {
+        return isc::dhcp::Dhcp6Parser::make_WHEN_NOT_PRESENT(driver.loc_);
+    }
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+    return isc::dhcp::Dhcp6Parser::make_STRING(tmp, driver.loc_);
+}
+
 \"Dhcp6\"  {
 \"Dhcp6\"  {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::CONFIG:
     case isc::dhcp::Parser6Context::CONFIG:

File diff suppressed because it is too large
+ 1566 - 1336
src/bin/dhcp6/dhcp6_parser.cc


+ 294 - 132
src/bin/dhcp6/dhcp6_parser.h

@@ -305,7 +305,8 @@ namespace isc { namespace dhcp {
     union union_type
     union union_type
     {
     {
       // value
       // value
-      // duid_type
+      // ncr_protocol_value
+      // replace_client_name_value
       char dummy1[sizeof(ElementPtr)];
       char dummy1[sizeof(ElementPtr)];
 
 
       // "boolean"
       // "boolean"
@@ -409,48 +410,62 @@ namespace isc { namespace dhcp {
         TOKEN_LIBRARY = 322,
         TOKEN_LIBRARY = 322,
         TOKEN_PARAMETERS = 323,
         TOKEN_PARAMETERS = 323,
         TOKEN_EXPIRED_LEASES_PROCESSING = 324,
         TOKEN_EXPIRED_LEASES_PROCESSING = 324,
-        TOKEN_RECLAIM_TIMER_WAIT_TIME = 325,
-        TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 326,
-        TOKEN_HOLD_RECLAIMED_TIME = 327,
-        TOKEN_MAX_RECLAIM_LEASES = 328,
-        TOKEN_MAX_RECLAIM_TIME = 329,
-        TOKEN_UNWARNED_RECLAIM_CYCLES = 330,
-        TOKEN_SERVER_ID = 331,
-        TOKEN_LLT = 332,
-        TOKEN_EN = 333,
-        TOKEN_LL = 334,
-        TOKEN_IDENTIFIER = 335,
-        TOKEN_HTYPE = 336,
-        TOKEN_TIME = 337,
-        TOKEN_ENTERPRISE_ID = 338,
-        TOKEN_DHCP4O6_PORT = 339,
-        TOKEN_CONTROL_SOCKET = 340,
-        TOKEN_SOCKET_TYPE = 341,
-        TOKEN_SOCKET_NAME = 342,
-        TOKEN_DHCP_DDNS = 343,
-        TOKEN_LOGGING = 344,
-        TOKEN_LOGGERS = 345,
-        TOKEN_OUTPUT_OPTIONS = 346,
-        TOKEN_OUTPUT = 347,
-        TOKEN_DEBUGLEVEL = 348,
-        TOKEN_SEVERITY = 349,
-        TOKEN_DHCP4 = 350,
-        TOKEN_DHCPDDNS = 351,
-        TOKEN_TOPLEVEL_JSON = 352,
-        TOKEN_TOPLEVEL_DHCP6 = 353,
-        TOKEN_SUB_DHCP6 = 354,
-        TOKEN_SUB_INTERFACES6 = 355,
-        TOKEN_SUB_SUBNET6 = 356,
-        TOKEN_SUB_POOL6 = 357,
-        TOKEN_SUB_PD_POOL = 358,
-        TOKEN_SUB_RESERVATION = 359,
-        TOKEN_SUB_OPTION_DEF = 360,
-        TOKEN_SUB_OPTION_DATA = 361,
-        TOKEN_SUB_HOOKS_LIBRARY = 362,
-        TOKEN_STRING = 363,
-        TOKEN_INTEGER = 364,
-        TOKEN_FLOAT = 365,
-        TOKEN_BOOLEAN = 366
+        TOKEN_SERVER_ID = 325,
+        TOKEN_IDENTIFIER = 326,
+        TOKEN_HTYPE = 327,
+        TOKEN_TIME = 328,
+        TOKEN_ENTERPRISE_ID = 329,
+        TOKEN_DHCP4O6_PORT = 330,
+        TOKEN_CONTROL_SOCKET = 331,
+        TOKEN_SOCKET_TYPE = 332,
+        TOKEN_SOCKET_NAME = 333,
+        TOKEN_DHCP_DDNS = 334,
+        TOKEN_ENABLE_UPDATES = 335,
+        TOKEN_QUALIFYING_SUFFIX = 336,
+        TOKEN_SERVER_IP = 337,
+        TOKEN_SERVER_PORT = 338,
+        TOKEN_SENDER_IP = 339,
+        TOKEN_SENDER_PORT = 340,
+        TOKEN_MAX_QUEUE_SIZE = 341,
+        TOKEN_NCR_PROTOCOL = 342,
+        TOKEN_NCR_FORMAT = 343,
+        TOKEN_ALWAYS_INCLUDE_FQDN = 344,
+        TOKEN_ALLOW_CLIENT_UPDATE = 345,
+        TOKEN_OVERRIDE_NO_UPDATE = 346,
+        TOKEN_OVERRIDE_CLIENT_UPDATE = 347,
+        TOKEN_REPLACE_CLIENT_NAME = 348,
+        TOKEN_GENERATED_PREFIX = 349,
+        TOKEN_UDP = 350,
+        TOKEN_TCP = 351,
+        TOKEN_JSON = 352,
+        TOKEN_WHEN_PRESENT = 353,
+        TOKEN_NEVER = 354,
+        TOKEN_ALWAYS = 355,
+        TOKEN_WHEN_NOT_PRESENT = 356,
+        TOKEN_LOGGING = 357,
+        TOKEN_LOGGERS = 358,
+        TOKEN_OUTPUT_OPTIONS = 359,
+        TOKEN_OUTPUT = 360,
+        TOKEN_DEBUGLEVEL = 361,
+        TOKEN_SEVERITY = 362,
+        TOKEN_DHCP4 = 363,
+        TOKEN_DHCPDDNS = 364,
+        TOKEN_TOPLEVEL_JSON = 365,
+        TOKEN_TOPLEVEL_DHCP6 = 366,
+        TOKEN_SUB_DHCP6 = 367,
+        TOKEN_SUB_INTERFACES6 = 368,
+        TOKEN_SUB_SUBNET6 = 369,
+        TOKEN_SUB_POOL6 = 370,
+        TOKEN_SUB_PD_POOL = 371,
+        TOKEN_SUB_RESERVATION = 372,
+        TOKEN_SUB_OPTION_DEF = 373,
+        TOKEN_SUB_OPTION_DATA = 374,
+        TOKEN_SUB_HOOKS_LIBRARY = 375,
+        TOKEN_SUB_DHCP_DDNS = 376,
+        TOKEN_STRING = 377,
+        TOKEN_INTEGER = 378,
+        TOKEN_FLOAT = 379,
+        TOKEN_BOOLEAN = 380
       };
       };
     };
     };
 
 
@@ -839,79 +854,131 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_RECLAIM_TIMER_WAIT_TIME (const location_type& l);
+    make_SERVER_ID (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_FLUSH_RECLAIMED_TIMER_WAIT_TIME (const location_type& l);
+    make_IDENTIFIER (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_HOLD_RECLAIMED_TIME (const location_type& l);
+    make_HTYPE (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MAX_RECLAIM_LEASES (const location_type& l);
+    make_TIME (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MAX_RECLAIM_TIME (const location_type& l);
+    make_ENTERPRISE_ID (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_UNWARNED_RECLAIM_CYCLES (const location_type& l);
+    make_DHCP4O6_PORT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SERVER_ID (const location_type& l);
+    make_CONTROL_SOCKET (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_LLT (const location_type& l);
+    make_SOCKET_TYPE (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_EN (const location_type& l);
+    make_SOCKET_NAME (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_LL (const location_type& l);
+    make_DHCP_DDNS (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_IDENTIFIER (const location_type& l);
+    make_ENABLE_UPDATES (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_HTYPE (const location_type& l);
+    make_QUALIFYING_SUFFIX (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_TIME (const location_type& l);
+    make_SERVER_IP (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_ENTERPRISE_ID (const location_type& l);
+    make_SERVER_PORT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_DHCP4O6_PORT (const location_type& l);
+    make_SENDER_IP (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_CONTROL_SOCKET (const location_type& l);
+    make_SENDER_PORT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SOCKET_TYPE (const location_type& l);
+    make_MAX_QUEUE_SIZE (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_SOCKET_NAME (const location_type& l);
+    make_NCR_PROTOCOL (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_DHCP_DDNS (const location_type& l);
+    make_NCR_FORMAT (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALWAYS_INCLUDE_FQDN (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALLOW_CLIENT_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_OVERRIDE_NO_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_OVERRIDE_CLIENT_UPDATE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_REPLACE_CLIENT_NAME (const location_type& l);
+
+    static inline
+    symbol_type
+    make_GENERATED_PREFIX (const location_type& l);
+
+    static inline
+    symbol_type
+    make_UDP (const location_type& l);
+
+    static inline
+    symbol_type
+    make_TCP (const location_type& l);
+
+    static inline
+    symbol_type
+    make_JSON (const location_type& l);
+
+    static inline
+    symbol_type
+    make_WHEN_PRESENT (const location_type& l);
+
+    static inline
+    symbol_type
+    make_NEVER (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALWAYS (const location_type& l);
+
+    static inline
+    symbol_type
+    make_WHEN_NOT_PRESENT (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
@@ -991,6 +1058,10 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
+    make_SUB_DHCP_DDNS (const location_type& l);
+
+    static inline
+    symbol_type
     make_STRING (const std::string& v, const location_type& l);
     make_STRING (const std::string& v, const location_type& l);
 
 
     static inline
     static inline
@@ -1210,12 +1281,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 661,     ///< Last index in yytable_.
-      yynnts_ = 281,  ///< Number of nonterminal symbols.
-      yyfinal_ = 24, ///< Termination state number.
+      yylast_ = 711,     ///< Last index in yytable_.
+      yynnts_ = 300,  ///< Number of nonterminal symbols.
+      yyfinal_ = 26, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 112  ///< Number of tokens.
+      yyntokens_ = 126  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1268,9 +1339,11 @@ namespace isc { namespace dhcp {
       75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
       75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
       85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
       85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
-     105,   106,   107,   108,   109,   110,   111
+     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125
     };
     };
-    const unsigned int user_token_number_max_ = 366;
+    const unsigned int user_token_number_max_ = 380;
     const token_number_type undef_token_ = 2;
     const token_number_type undef_token_ = 2;
 
 
     if (static_cast<int>(t) <= yyeof_)
     if (static_cast<int>(t) <= yyeof_)
@@ -1303,24 +1376,25 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 125: // value
-      case 350: // duid_type
+      case 140: // value
+      case 388: // ncr_protocol_value
+      case 397: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 111: // "boolean"
+      case 125: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 110: // "floating point"
+      case 124: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 109: // "integer"
+      case 123: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 108: // "constant string"
+      case 122: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1341,24 +1415,25 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 125: // value
-      case 350: // duid_type
+      case 140: // value
+      case 388: // ncr_protocol_value
+      case 397: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 111: // "boolean"
+      case 125: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 110: // "floating point"
+      case 124: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 109: // "integer"
+      case 123: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 108: // "constant string"
+      case 122: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1438,24 +1513,25 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 125: // value
-      case 350: // duid_type
+      case 140: // value
+      case 388: // ncr_protocol_value
+      case 397: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 111: // "boolean"
+      case 125: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 110: // "floating point"
+      case 124: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 109: // "integer"
+      case 123: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 108: // "constant string"
+      case 122: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1482,24 +1558,25 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 125: // value
-      case 350: // duid_type
+      case 140: // value
+      case 388: // ncr_protocol_value
+      case 397: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 111: // "boolean"
+      case 125: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 110: // "floating point"
+      case 124: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 109: // "integer"
+      case 123: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 108: // "constant string"
+      case 122: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1569,7 +1646,8 @@ namespace isc { namespace dhcp {
      335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
      335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
      345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
      345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
      355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
      355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
-     365,   366
+     365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
+     375,   376,   377,   378,   379,   380
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -1983,117 +2061,195 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_RECLAIM_TIMER_WAIT_TIME (const location_type& l)
+  Dhcp6Parser::make_SERVER_ID (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_RECLAIM_TIMER_WAIT_TIME, l);
+    return symbol_type (token::TOKEN_SERVER_ID, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_FLUSH_RECLAIMED_TIMER_WAIT_TIME (const location_type& l)
+  Dhcp6Parser::make_IDENTIFIER (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME, l);
+    return symbol_type (token::TOKEN_IDENTIFIER, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_HOLD_RECLAIMED_TIME (const location_type& l)
+  Dhcp6Parser::make_HTYPE (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_HOLD_RECLAIMED_TIME, l);
+    return symbol_type (token::TOKEN_HTYPE, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_MAX_RECLAIM_LEASES (const location_type& l)
+  Dhcp6Parser::make_TIME (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_MAX_RECLAIM_LEASES, l);
+    return symbol_type (token::TOKEN_TIME, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_MAX_RECLAIM_TIME (const location_type& l)
+  Dhcp6Parser::make_ENTERPRISE_ID (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_MAX_RECLAIM_TIME, l);
+    return symbol_type (token::TOKEN_ENTERPRISE_ID, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_UNWARNED_RECLAIM_CYCLES (const location_type& l)
+  Dhcp6Parser::make_DHCP4O6_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_UNWARNED_RECLAIM_CYCLES, l);
+    return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_SERVER_ID (const location_type& l)
+  Dhcp6Parser::make_CONTROL_SOCKET (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SERVER_ID, l);
+    return symbol_type (token::TOKEN_CONTROL_SOCKET, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_SOCKET_TYPE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SOCKET_TYPE, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_LLT (const location_type& l)
+  Dhcp6Parser::make_SOCKET_NAME (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_LLT, l);
+    return symbol_type (token::TOKEN_SOCKET_NAME, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_EN (const location_type& l)
+  Dhcp6Parser::make_DHCP_DDNS (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_EN, l);
+    return symbol_type (token::TOKEN_DHCP_DDNS, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_LL (const location_type& l)
+  Dhcp6Parser::make_ENABLE_UPDATES (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_LL, l);
+    return symbol_type (token::TOKEN_ENABLE_UPDATES, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_IDENTIFIER (const location_type& l)
+  Dhcp6Parser::make_QUALIFYING_SUFFIX (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_IDENTIFIER, l);
+    return symbol_type (token::TOKEN_QUALIFYING_SUFFIX, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_HTYPE (const location_type& l)
+  Dhcp6Parser::make_SERVER_IP (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_HTYPE, l);
+    return symbol_type (token::TOKEN_SERVER_IP, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_TIME (const location_type& l)
+  Dhcp6Parser::make_SERVER_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_TIME, l);
+    return symbol_type (token::TOKEN_SERVER_PORT, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_ENTERPRISE_ID (const location_type& l)
+  Dhcp6Parser::make_SENDER_IP (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_ENTERPRISE_ID, l);
+    return symbol_type (token::TOKEN_SENDER_IP, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_DHCP4O6_PORT (const location_type& l)
+  Dhcp6Parser::make_SENDER_PORT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
+    return symbol_type (token::TOKEN_SENDER_PORT, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_CONTROL_SOCKET (const location_type& l)
+  Dhcp6Parser::make_MAX_QUEUE_SIZE (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_CONTROL_SOCKET, l);
+    return symbol_type (token::TOKEN_MAX_QUEUE_SIZE, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_SOCKET_TYPE (const location_type& l)
+  Dhcp6Parser::make_NCR_PROTOCOL (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SOCKET_TYPE, l);
+    return symbol_type (token::TOKEN_NCR_PROTOCOL, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_SOCKET_NAME (const location_type& l)
+  Dhcp6Parser::make_NCR_FORMAT (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_SOCKET_NAME, l);
+    return symbol_type (token::TOKEN_NCR_FORMAT, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_DHCP_DDNS (const location_type& l)
+  Dhcp6Parser::make_ALWAYS_INCLUDE_FQDN (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_DHCP_DDNS, l);
+    return symbol_type (token::TOKEN_ALWAYS_INCLUDE_FQDN, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_ALLOW_CLIENT_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALLOW_CLIENT_UPDATE, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_OVERRIDE_CLIENT_UPDATE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_OVERRIDE_CLIENT_UPDATE, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_REPLACE_CLIENT_NAME (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_REPLACE_CLIENT_NAME, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_GENERATED_PREFIX (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_GENERATED_PREFIX, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_UDP (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_UDP, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_TCP (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_TCP, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_JSON (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_JSON, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_WHEN_PRESENT (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_WHEN_PRESENT, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_NEVER (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_NEVER, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_ALWAYS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALWAYS, l);
+  }
+
+  Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_WHEN_NOT_PRESENT (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_WHEN_NOT_PRESENT, l);
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
@@ -2211,6 +2367,12 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_SUB_DHCP_DDNS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SUB_DHCP_DDNS, l);
+  }
+
+  Dhcp6Parser::symbol_type
   Dhcp6Parser::make_STRING (const std::string& v, const location_type& l)
   Dhcp6Parser::make_STRING (const std::string& v, const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_STRING, v, l);
     return symbol_type (token::TOKEN_STRING, v, l);
@@ -2237,7 +2399,7 @@ namespace isc { namespace dhcp {
 
 
 #line 14 "dhcp6_parser.yy" // lalr1.cc:377
 #line 14 "dhcp6_parser.yy" // lalr1.cc:377
 } } // isc::dhcp
 } } // isc::dhcp
-#line 2241 "dhcp6_parser.h" // lalr1.cc:377
+#line 2403 "dhcp6_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 176 - 22
src/bin/dhcp6/dhcp6_parser.yy

@@ -142,26 +142,28 @@ using namespace std;
   SOCKET_NAME "socket-name"
   SOCKET_NAME "socket-name"
 
 
   DHCP_DDNS "dhcp-ddns"
   DHCP_DDNS "dhcp-ddns"
-
- /// @todo: Implement proper parsing for those parameters in Dhcp6/dhcp-ddns/*.
- /// This should be part of the #5043 ticket. Listing the keywords here for
- /// completeness.
-
- // These are tokens defined in Dhcp6/dhcp-ddns/*
- // They're not
- //  ENABLE_UPDATES "enable-updates"
- //  SERVER_IP "server-ip"
- //  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"
- //  OVERRDIDE_NO_UPDATE "override-no-update"
- //  OVERRDIDE_CLIENT_UPDATE "override-client-update"
- //  REPLACE_CLIENT_NAME "replace-client-name"
- //  GENERATED_PREFIX "generated-prefix"
- //  QUALIFYING_SUFFIX "qualifying-suffix"
+  ENABLE_UPDATES "enable-updates"
+  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"
+  ALLOW_CLIENT_UPDATE "allow-client-update"
+  OVERRIDE_NO_UPDATE "override-no-update"
+  OVERRIDE_CLIENT_UPDATE "override-client-update"
+  REPLACE_CLIENT_NAME "replace-client-name"
+  GENERATED_PREFIX "generated-prefix"
+  UDP "UDP"
+  TCP "TCP"
+  JSON "JSON"
+  WHEN_PRESENT "when-present"
+  NEVER "never"
+  ALWAYS "always"
+  WHEN_NOT_PRESENT "when-not-present"
 
 
   LOGGING "Logging"
   LOGGING "Logging"
   LOGGERS "loggers"
   LOGGERS "loggers"
@@ -186,6 +188,7 @@ using namespace std;
   SUB_OPTION_DEF
   SUB_OPTION_DEF
   SUB_OPTION_DATA
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_HOOKS_LIBRARY
+  SUB_DHCP_DDNS
 ;
 ;
 
 
 %token <std::string> STRING "constant string"
 %token <std::string> STRING "constant string"
@@ -195,6 +198,8 @@ using namespace std;
 
 
 %type <ElementPtr> value
 %type <ElementPtr> value
 %type <ElementPtr> duid_type
 %type <ElementPtr> duid_type
+%type <ElementPtr> ncr_protocol_value
+%type <ElementPtr> replace_client_name_value
 
 
 %printer { yyoutput << $$; } <*>;
 %printer { yyoutput << $$; } <*>;
 
 
@@ -216,6 +221,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
+     | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
      ;
      ;
 
 
 // ---- generic JSON parser ---------------------------------
 // ---- generic JSON parser ---------------------------------
@@ -1467,12 +1473,160 @@ dhcp_ddns: DHCP_DDNS {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
-    ctx.enter(ctx.NO_KEYWORD);
-} COLON LCURLY_BRACKET not_empty_map RCURLY_BRACKET {
+    ctx.enter(ctx.DHCP_DDNS);
+} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+sub_dhcp_ddns: LCURLY_BRACKET {
+    // Parse the dhcp-ddns map
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} dhcp_ddns_params RCURLY_BRACKET {
+    // parsing completed
+};
+
+dhcp_ddns_params: dhcp_ddns_param
+                | dhcp_ddns_params COMMA dhcp_ddns_param
+                ;
+
+dhcp_ddns_param: enable_updates
+               | qualifying_suffix
+               | server_ip
+               | server_port
+               | sender_ip
+               | sender_port
+               | max_queue_size
+               | ncr_protocol
+               | ncr_format
+               | always_include_fqdn
+               | allow_client_update
+               | override_no_update
+               | override_client_update
+               | replace_client_name
+               | generated_prefix
+               | unknown_map_entry
+               ;
+
+enable_updates: ENABLE_UPDATES COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("enable-updates", b);
+};
+
+qualifying_suffix: QUALIFYING_SUFFIX {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("qualifying-suffix", s);
+    ctx.leave();
+};
+
+server_ip: SERVER_IP {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("server-ip", s);
+    ctx.leave();
+};
+
+server_port: SERVER_PORT COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("server-port", i);
+};
+
+sender_ip: SENDER_IP {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("sender-ip", s);
+    ctx.leave();
+};
+
+sender_port: SENDER_PORT COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("sender-port", i);
+};
+
+max_queue_size: MAX_QUEUE_SIZE COLON INTEGER {
+    ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("max-queue-size", i);
+};
+
+ncr_protocol: NCR_PROTOCOL {
+    ctx.enter(ctx.NCR_PROTOCOL);
+} COLON ncr_protocol_value {
+    ctx.stack_.back()->set("ncr-protocol", $4);
+    ctx.leave();
+};
+
+ncr_protocol_value:
+    UDP { $$ = ElementPtr(new StringElement("UDP", ctx.loc2pos(@1))); }
+  | TCP { $$ = ElementPtr(new StringElement("TCP", ctx.loc2pos(@1))); }
+  ;
+
+ncr_format: NCR_FORMAT {
+    ctx.enter(ctx.NCR_FORMAT);
+} COLON JSON {
+    ElementPtr json(new StringElement("JSON", ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("ncr-format", json);
+    ctx.leave();
+};
+
+always_include_fqdn: ALWAYS_INCLUDE_FQDN COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("always-include-fqdn", b);
+};
+
+allow_client_update: ALLOW_CLIENT_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("allow-client-update",  b);
+};
+
+override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("override-no-update", b);
+};
+
+override_client_update: OVERRIDE_CLIENT_UPDATE COLON BOOLEAN {
+    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("override-client-update", b);
+};
+
+replace_client_name: REPLACE_CLIENT_NAME {
+    ctx.enter(ctx.REPLACE_CLIENT_NAME);
+} COLON replace_client_name_value {
+    ctx.stack_.back()->set("replace-client-name", $4);
+    ctx.leave();
+};
+
+replace_client_name_value:
+    WHEN_PRESENT {
+      $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1))); 
+      }
+  | NEVER {
+      $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1)));
+      }
+  | ALWAYS {
+      $$ = ElementPtr(new StringElement("always", ctx.loc2pos(@1)));
+      }
+  | WHEN_NOT_PRESENT {
+      $$ = ElementPtr(new StringElement("when-not-present", ctx.loc2pos(@1)));
+      }
+  | BOOLEAN  {
+      error(@1, "boolean values for the replace-client-name are "
+                "no longer supported");
+      }
+  ;
+
+generated_prefix: GENERATED_PREFIX {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("generated-prefix", s);
+    ctx.leave();
+};
+
 // JSON entries for Dhcp4 and DhcpDdns
 // JSON entries for Dhcp4 and DhcpDdns
 
 
 dhcp4_json_object: DHCP4 {
 dhcp4_json_object: DHCP4 {

+ 17 - 2
src/bin/dhcp6/json_config_parser.cc

@@ -710,9 +710,8 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
     } else if (config_id.compare("hosts-database") == 0) {
     } else if (config_id.compare("hosts-database") == 0) {
         parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB);
         parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB);
     // hooks-libraries is now converted to SimpleParser.
     // hooks-libraries is now converted to SimpleParser.
-    } else if (config_id.compare("dhcp-ddns") == 0) {
-        parser = new D2ClientConfigParser(config_id);
     // mac-source has been converted to SimpleParser.
     // mac-source has been converted to SimpleParser.
+    // dhcp-ddns has been converted to SimpleParser
     } else if (config_id.compare("relay-supplied-options") == 0) {
     } else if (config_id.compare("relay-supplied-options") == 0) {
         parser = new RSOOListConfigParser(config_id);
         parser = new RSOOListConfigParser(config_id);
     // control-socket has been converted to SimpleParser.
     // control-socket has been converted to SimpleParser.
@@ -949,6 +948,17 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
                 continue;
                 continue;
             }
             }
 
 
+            if (config_pair.first == "dhcp-ddns") {
+                // Apply defaults if not in short cut
+                if (!D2ClientConfigParser::isShortCutDisabled(config_pair.second)) {
+                    D2ClientConfigParser::setAllDefaults(config_pair.second);
+                }
+                D2ClientConfigParser parser;
+                D2ClientConfigPtr cfg = parser.parse(config_pair.second);
+                CfgMgr::instance().getStagingCfg()->setD2ClientConfig(cfg);
+                continue;
+            }
+
             ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
             ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
                                                            config_pair.second));
                                                            config_pair.second));
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
@@ -1036,6 +1046,11 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
             // revert it.  As a result, the failure to commit a subsequent
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
             // change causes problems when trying to roll back.
             hooks_parser.loadLibraries();
             hooks_parser.loadLibraries();
+
+            // Apply staged D2ClientConfig, used to be done by parser commit
+            D2ClientConfigPtr cfg;
+            cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
+            CfgMgr::instance().setD2ClientConfig(cfg);
         }
         }
         catch (const isc::Exception& ex) {
         catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());

+ 1 - 1
src/bin/dhcp6/location.hh

@@ -1,4 +1,4 @@
-// Generated 201701102225
+// Generated 201701131911
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Locations for Bison parsers in C++
 // Locations for Bison parsers in C++

+ 8 - 0
src/bin/dhcp6/parser_context.cc

@@ -167,6 +167,14 @@ Parser6Context::contextName()
         return ("loggers");
         return ("loggers");
     case OUTPUT_OPTIONS:
     case OUTPUT_OPTIONS:
         return ("output-options");
         return ("output-options");
+    case DHCP_DDNS:
+        return ("dhcp-ddns");
+    case NCR_PROTOCOL:
+        return ("ncr-protocol");
+    case NCR_FORMAT:
+        return ("ncr-format");
+    case REPLACE_CLIENT_NAME:
+        return ("replace-client-name");
     default:
     default:
         return ("__unknown__");
         return ("__unknown__");
     }
     }

+ 19 - 4
src/bin/dhcp6/parser_context.h

@@ -83,7 +83,10 @@ public:
         PARSER_OPTION_DATA,
         PARSER_OPTION_DATA,
 
 
         /// This will parse the input as hooks-library.
         /// This will parse the input as hooks-library.
-        PARSER_HOOKS_LIBRARY
+        PARSER_HOOKS_LIBRARY,
+
+        /// This will parse the input as dhcp-ddns. (D2 client config)
+        PARSER_DHCP_DDNS
     } ParserType;
     } ParserType;
 
 
     /// @brief Default constructor.
     /// @brief Default constructor.
@@ -187,8 +190,7 @@ public:
         ///< Used while parsing content of Dhcp6.
         ///< Used while parsing content of Dhcp6.
         DHCP6,
         DHCP6,
 
 
-        // not yet DHCP4,
-        // not yet DHCP_DDNS,
+        // not yet Dhcp4, DhcpDdns,
 
 
         ///< Used while parsing content of Logging
         ///< Used while parsing content of Logging
         LOGGING,
         LOGGING,
@@ -256,7 +258,20 @@ public:
         LOGGERS,
         LOGGERS,
 
 
         /// Used while parsing Logging/loggers/output_options structures.
         /// Used while parsing Logging/loggers/output_options structures.
-        OUTPUT_OPTIONS
+        OUTPUT_OPTIONS,
+
+        /// Used while parsing Dhcp6/dhcp-ddns.
+        DHCP_DDNS,
+
+        /// Used while parsing Dhcp6/dhcp-ddns/ncr-protocol
+        NCR_PROTOCOL,
+
+        /// Used while parsing Dhcp6/dhcp-ddns/ncr-format
+        NCR_FORMAT,
+
+        /// Used while parsing Dhcp6/dhcp-ddns/replace-client-name.
+        REPLACE_CLIENT_NAME
+
     } ParserContext;
     } ParserContext;
 
 
     /// @brief File name
     /// @brief File name

+ 1 - 1
src/bin/dhcp6/position.hh

@@ -1,4 +1,4 @@
-// Generated 201701102225
+// Generated 201701131911
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Positions for Bison parsers in C++
 // Positions for Bison parsers in C++

+ 1 - 1
src/bin/dhcp6/stack.hh

@@ -1,4 +1,4 @@
-// Generated 201701102225
+// Generated 201701131911
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Stack handling for Bison parsers in C++
 // Stack handling for Bison parsers in C++

+ 2 - 2
src/bin/dhcp6/tests/d2_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -117,7 +117,7 @@ Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "     \"allow-client-update\" : true, "
         "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
-        "     \"replace-client-name\" : true, "
+        "     \"replace-client-name\" : \"when-present\", "
         "     \"generated-prefix\" : \"test.prefix\", "
         "     \"generated-prefix\" : \"test.prefix\", "
         "     \"qualifying-suffix\" : \"test.suffix.\" },"
         "     \"qualifying-suffix\" : \"test.suffix.\" },"
         "\"valid-lifetime\": 4000 }";
         "\"valid-lifetime\": 4000 }";

+ 12 - 28
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -391,10 +391,8 @@ public:
     // in a client request correctly, according to the replace-client-name
     // in a client request correctly, according to the replace-client-name
     // mode configuration parameter.
     // mode configuration parameter.
     //
     //
-    // @param mode - value to use client-name-replacment parameter - for
-    // mode labels such as NEVER and ALWAYS must incluce enclosing quotes:
-    // "\"NEVER\"".  This allows us to also pass in boolean literals which
-    // are unquoted.
+    // @param mode - value to use for replace-client-name mode
+    //
     // @param client_name_flag - specifies whether or not the client request
     // @param client_name_flag - specifies whether or not the client request
     // should contain a hostname option
     // should contain a hostname option
     // @param exp_replacement_flag - specifies whether or not the server is
     // @param exp_replacement_flag - specifies whether or not the server is
@@ -420,7 +418,7 @@ public:
             "\"dhcp-ddns\": { \n"
             "\"dhcp-ddns\": { \n"
             "\"enable-updates\": true, \n"
             "\"enable-updates\": true, \n"
             "\"qualifying-suffix\": \"fake-suffix.isc.org.\", \n"
             "\"qualifying-suffix\": \"fake-suffix.isc.org.\", \n"
-            "\"replace-client-name\": %s \n"
+            "\"replace-client-name\": \"%s\" \n"
             "}} \n";
             "}} \n";
 
 
         // Create the configuration and configure the server
         // Create the configuration and configure the server
@@ -1494,39 +1492,25 @@ TEST_F(FqdnDhcpv6SrvTest, hostnameReservationDdnsDisabled) {
 TEST_F(FqdnDhcpv6SrvTest, replaceClientNameModeTest) {
 TEST_F(FqdnDhcpv6SrvTest, replaceClientNameModeTest) {
     isc::dhcp::test::IfaceMgrTestConfig test_config(true);
     isc::dhcp::test::IfaceMgrTestConfig test_config(true);
 
 
-    // We pass mode labels in with enclosing quotes so we can also test
-    // unquoted boolean literals true/false
-    testReplaceClientNameMode("\"never\"",
+    testReplaceClientNameMode("never",
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("\"never\"",
+    testReplaceClientNameMode("never",
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
 
 
-    testReplaceClientNameMode("\"always\"",
+    testReplaceClientNameMode("always",
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
-    testReplaceClientNameMode("\"always\"",
+    testReplaceClientNameMode("always",
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
 
 
-    testReplaceClientNameMode("\"when-present\"",
+    testReplaceClientNameMode("when-present",
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("\"when-present\"",
+    testReplaceClientNameMode("when-present",
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_REPLACED);
 
 
-    testReplaceClientNameMode("\"when-not-present\"",
+    testReplaceClientNameMode("when-not-present",
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
                               CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
-    testReplaceClientNameMode("\"when-not-present\"",
-                              CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
-
-    // Verify that boolean false produces the same result as RCM_NEVER
-    testReplaceClientNameMode("false",
-                              CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("false",
+    testReplaceClientNameMode("when-not-present",
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
                               CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
-
-    // Verify that boolean true produces the same result as RCM_WHEN_PRESENT
-    testReplaceClientNameMode("true",
-                              CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
-    testReplaceClientNameMode("true",
-                              CLIENT_NAME_PRESENT, NAME_REPLACED);
 }
 }
 
 
 }   // end of anonymous namespace
 }   // end of anonymous namespace

+ 1 - 0
src/bin/dhcp6/tests/parser_unittest.cc

@@ -257,6 +257,7 @@ TEST(ParserTest, file) {
     configs.push_back("several-subnets.json");
     configs.push_back("several-subnets.json");
     configs.push_back("simple.json");
     configs.push_back("simple.json");
     configs.push_back("stateless.json");
     configs.push_back("stateless.json");
+    configs.push_back("with-ddns.json");
 
 
     for (int i = 0; i<configs.size(); i++) {
     for (int i = 0; i<configs.size(); i++) {
         testFile(string(CFG_EXAMPLES) + "/" + configs[i]);
         testFile(string(CFG_EXAMPLES) + "/" + configs[i]);

+ 11 - 1
src/lib/dhcpsrv/cfgmgr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -82,7 +82,17 @@ CfgMgr::isDuplicate(const Subnet6& subnet) const {
 
 
 void
 void
 CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
 CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
+    ensureCurrentAllocated();
+    // Note that D2ClientMgr::setD2Config() actually attempts to apply the
+    // configuration by stopping its sender and opening a new one and so
+    // forth per the new configuration.
     d2_client_mgr_.setD2ClientConfig(new_config);
     d2_client_mgr_.setD2ClientConfig(new_config);
+
+    // Manager will throw if the set fails, if it succeeds
+    // we'll update our SrvConfig, configuration_, with the D2ClientConfig
+    // used. This is largely bookkeeping in case we ever want to compare
+    // configuration_ to another SrvConfig.
+    configuration_->setD2ClientConfig(new_config);
 }
 }
 
 
 bool
 bool

+ 6 - 1
src/lib/dhcpsrv/cfgmgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -148,6 +148,11 @@ public:
 
 
     /// @brief Updates the DHCP-DDNS client configuration to the given value.
     /// @brief Updates the DHCP-DDNS client configuration to the given value.
     ///
     ///
+    /// Passes the new configuration to the D2ClientMgr instance,
+    /// d2_client_mgr_, which will attempt to apply the new configuration
+    /// by shutting down its sender and opening a new connection per the new
+    /// configuration (see @c D2ClientMgr::setD2ClientConfig()).
+    ///
     /// @param new_config pointer to the new client configuration.
     /// @param new_config pointer to the new client configuration.
     ///
     ///
     /// @throw Underlying method(s) will throw D2ClientError if given an empty
     /// @throw Underlying method(s) will throw D2ClientError if given an empty

+ 238 - 148
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -1222,133 +1222,222 @@ SubnetConfigParser::getOptionalParam(const std::string& name) {
 }
 }
 
 
 //**************************** D2ClientConfigParser **********************
 //**************************** D2ClientConfigParser **********************
-D2ClientConfigParser::D2ClientConfigParser(const std::string& entry_name)
-    : entry_name_(entry_name), boolean_values_(new BooleanStorage()),
-      uint32_values_(new Uint32Storage()), string_values_(new StringStorage()),
-      local_client_config_() {
+
+namespace {
+
+template <typename int_type> int_type
+getInt(const std::string& name, ConstElementPtr value) {
+    int64_t val_int = value->intValue();
+    if ((val_int < std::numeric_limits<int_type>::min()) ||
+        (val_int > std::numeric_limits<int_type>::max())) {
+        isc_throw(DhcpConfigError, "out of range value (" << val_int
+                  << ") specified for parameter '" << name
+                  << "' (" << value->getPosition() << ")");
+    }
+    return (static_cast<int_type>(val_int));
 }
 }
 
 
-D2ClientConfigParser::~D2ClientConfigParser() {
+uint32_t
+getUint32(const std::string& name, ConstElementPtr value) {
+    return (getInt<uint32_t>(name, value));
 }
 }
 
 
-void
-D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
-    BOOST_FOREACH(ConfigPair param, client_config->mapValue()) {
-        ParserPtr parser;
-        try {
-            parser = createConfigParser(param.first);
-        } catch (std::exception& ex) {
-            // Catch exception in case the configuration contains the
-            // unsupported parameter. In this case, we will need to
-            // append the position of this element.
-            isc_throw(DhcpConfigError, ex.what() << " ("
-                      << param.second->getPosition() << ")");
-        }
+IOAddress
+getIOAddress(const std::string& name, ConstElementPtr value) {
+    std::string str = value->stringValue();
+    try {
+        return (IOAddress(str));
+    } catch (const std::exception& ex) {
+        isc_throw(DhcpConfigError, "invalid address (" << str
+                  << ") specified for parameter '" << name
+                  << "' (" << value->getPosition() << ")");
+    }
+}
 
 
-        parser->build(param.second);
-        parser->commit();
+dhcp_ddns::NameChangeProtocol
+getProtocol(const std::string& name, ConstElementPtr value) {
+    std::string str = value->stringValue();
+    try {
+        return (dhcp_ddns::stringToNcrProtocol(str));
+    } catch (const std::exception& ex) {
+        isc_throw(DhcpConfigError,
+                  "invalid NameChangeRequest protocol (" << str
+                  << ") specified for parameter '" << name
+                  << "' (" << value->getPosition() << ")");
     }
     }
+}
 
 
-    /// @todo Create configuration from the configuration parameters. Because
-    /// the validation of the D2 configuration is atomic, there is no way to
-    /// tell which parameter is invalid. Therefore, we catch all exceptions
-    /// and append the line number of the parent element. In the future we
-    /// may should extend D2ClientConfig code so as it returns the name of
-    /// the invalid parameter.
+dhcp_ddns::NameChangeFormat
+getFormat(const std::string& name, ConstElementPtr value) {
+    std::string str = value->stringValue();
     try {
     try {
-        bool enable_updates = boolean_values_->getParam("enable-updates");
-        if (!enable_updates && (client_config->mapValue().size() == 1)) {
-            // If enable-updates is the only parameter and it is false then
-            // we're done.  This allows for an abbreviated configuration entry
-            // that only contains that flag.  Use the default D2ClientConfig
-            // constructor to a create a disabled instance.
-            local_client_config_.reset(new D2ClientConfig());
-
-            return;
-        }
+        return (dhcp_ddns::stringToNcrFormat(str));
+    } catch (const std::exception& ex) {
+        isc_throw(DhcpConfigError,
+                  "invalid NameChangeRequest format (" << str
+                  << ") specified for parameter '" << name
+                  << "' (" << value->getPosition() << ")");
+    }
+}
+
+D2ClientConfig::ReplaceClientNameMode
+getMode(const std::string& name, ConstElementPtr value) {
+    std::string str = value->stringValue();
+    try {
+        return (D2ClientConfig::stringToReplaceClientNameMode(str));
+    } catch (const std::exception& ex) {
+        isc_throw(DhcpConfigError,
+                  "invalid ReplaceClientName mode (" << str
+                  << ") specified for parameter '" << name
+                  << "' (" << value->getPosition() << ")");
+    }
+}
 
 
-        // Get all parameters that are needed to create the D2ClientConfig.
+};
 
 
-        // The qualifying suffix is mandatory when updates are enabled
-        std::string qualifying_suffix =
-            string_values_->getParam("qualifying-suffix");
+D2ClientConfigPtr
+D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
+    D2ClientConfigPtr new_config;
+    
+    if (isShortCutDisabled(client_config)) {
+      // If enable-updates is the only parameter and it is false then
+      // we're done.  This allows for an abbreviated configuration entry
+      // that only contains that flag.  Use the default D2ClientConfig
+      // constructor to a create a disabled instance.
+      new_config.reset(new D2ClientConfig());
+      return (new_config);
+    }
+
+    // As isShortCutDisabled() was called this cannot fail
+    bool enable_updates = client_config->get("enable-updates")->boolValue();
+
+    // Get all parameters that are needed to create the D2ClientConfig.
+    std::string qualifying_suffix;
+    bool found_qualifying_suffix = false;
+    IOAddress server_ip(0);
+    uint32_t server_port;
+    std::string sender_ip_str;
+    uint32_t sender_port;
+    uint32_t max_queue_size;
+    dhcp_ddns::NameChangeProtocol ncr_protocol;
+    dhcp_ddns::NameChangeFormat ncr_format;
+    bool always_include_fqdn;
+    bool allow_client_update;
+    bool override_no_update;
+    bool override_client_update;
+    D2ClientConfig::ReplaceClientNameMode replace_client_name_mode;
+    std::string generated_prefix;
 
 
-        IOAddress server_ip =
-            IOAddress(string_values_->getOptionalParam("server-ip",
-                                                       D2ClientConfig::
-                                                       DFT_SERVER_IP));
+    BOOST_FOREACH(ConfigPair param, client_config->mapValue()) {
+        std::string entry(param.first);
+        ConstElementPtr value(param.second);
+        try {
+            if (entry == "enable-updates") {
+                // already done.
+            } else if (entry == "qualifying-suffix") {
+                qualifying_suffix = value->stringValue();
+                found_qualifying_suffix = true;
+            } else if (entry == "server-ip") {
+                server_ip = getIOAddress("server-ip", value);
+            } else if (entry == "server-port") {
+                server_port = getUint32("server-port", value);
+            } else if (entry == "sender-ip") {
+                sender_ip_str = value->stringValue();
+            } else if (entry == "sender-port") {
+                sender_port = getUint32("sender-port", value);
+            } else if (entry == "max-queue-size") {
+                max_queue_size = getUint32("max-queue-size", value);
+            } else if (entry == "ncr-protocol") {
+                ncr_protocol = getProtocol("ncr-protocol", value);
+            } else if (entry == "ncr-format") {
+                ncr_format = getFormat("ncr-format", value);
+            } else if (entry == "always-include-fqdn") {
+                always_include_fqdn = value->boolValue();
+            } else if (entry == "allow-client-update") {
+                allow_client_update = value->boolValue();
+                // currently unused
+                (void)allow_client_update;
+            } else if (entry == "override-no-update") {
+                override_no_update = value->boolValue();
+            } else if (entry == "override-client-update") {
+                override_client_update = value->boolValue();
+            } else if (entry == "replace-client-name") {
+                replace_client_name_mode = getMode("replace-client-name", value);
+            } else if (entry == "generated-prefix") {
+                generated_prefix = value->stringValue();
+            } else {
+                isc_throw(DhcpConfigError,
+                          "unsupported parameter '" << entry
+                          << " (" << value->getPosition() << ")");
+            }
+        } catch (const isc::data::TypeError&) {
+            isc_throw(DhcpConfigError,
+                      "invalid value type specified for parameter '" << entry
+                      << " (" << value->getPosition() << ")");
+        }
+    }
 
 
-        uint32_t server_port =
-            uint32_values_->getOptionalParam("server-port",
-                                             D2ClientConfig::DFT_SERVER_PORT);
+    // Qualifying-suffix is required when updates are enabled
+    if (enable_updates && !found_qualifying_suffix) {
+        isc_throw(DhcpConfigError,
+                  "parameter 'qualifying-suffix' is required when "
+                  "updates are enabled ("
+                  << client_config->getPosition() << ")");
+    }
 
 
+    IOAddress sender_ip(0);
+    if (sender_ip_str.empty()) {
         // The default sender IP depends on the server IP family
         // 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",
-                                                            D2ClientConfig::
-                                                            DFT_NCR_PROTOCOL));
-        dhcp_ddns::NameChangeFormat ncr_format
-            = dhcp_ddns::stringToNcrFormat(string_values_->
-                                           getOptionalParam("ncr-format",
-                                                            D2ClientConfig::
-                                                            DFT_NCR_FORMAT));
-        std::string generated_prefix =
-            string_values_->getOptionalParam("generated-prefix",
-                                             D2ClientConfig::
-                                             DFT_GENERATED_PREFIX);
-        bool always_include_fqdn =
-            boolean_values_->getOptionalParam("always-include-fqdn",
-                                                D2ClientConfig::
-                                                DFT_ALWAYS_INCLUDE_FQDN);
-
-        bool override_no_update =
-            boolean_values_->getOptionalParam("override-no-update",
-                                              D2ClientConfig::
-                                              DFT_OVERRIDE_NO_UPDATE);
-
-        bool override_client_update =
-            boolean_values_->getOptionalParam("override-client-update",
-                                              D2ClientConfig::
-                                              DFT_OVERRIDE_CLIENT_UPDATE);
-
-        // Formerly, replace-client-name was boolean, so for now we'll support boolean
-        // values by mapping them to the appropriate mode
-        D2ClientConfig::ReplaceClientNameMode replace_client_name_mode;
-        std::string mode_str;
-        mode_str  = string_values_->getOptionalParam("replace-client-name",
-                                                     D2ClientConfig::
-                                                     DFT_REPLACE_CLIENT_NAME_MODE);
-        if (boost::iequals(mode_str, "false")) {
-            // @todo add a debug log
-            replace_client_name_mode = D2ClientConfig::RCM_NEVER;
-        }
-        else if (boost::iequals(mode_str, "true")) {
-            // @todo add a debug log
-            replace_client_name_mode = D2ClientConfig::RCM_WHEN_PRESENT;
-        } else {
-            replace_client_name_mode = D2ClientConfig::
-                                       stringToReplaceClientNameMode(mode_str);
+        sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() :
+                                        IOAddress::IPV6_ZERO_ADDRESS());
+    } else {
+        try {
+            sender_ip = IOAddress(sender_ip_str);
+        } catch (const std::exception& ex) {
+            isc_throw(DhcpConfigError, "invalid address (" << sender_ip_str
+                      << ") specified for parameter 'sender-ip' ("
+                      << getPosition("sender-ip", client_config) << ")");
         }
         }
+    }
+
+    // Now we check for logical errors. This repeats what is done in
+    // D2ClientConfig::validate(), but doing it here permits us to
+    // emit meaningful parameter position info in the error.
+    if (ncr_format != dhcp_ddns::FMT_JSON) {
+        isc_throw(D2ClientError, "D2ClientConfig error: NCR Format: "
+                  << dhcp_ddns::ncrFormatToString(ncr_format)
+                  << " is not supported. ("
+                  << getPosition("ncr-format", client_config) << ")");
+    }
 
 
+    if (ncr_protocol != dhcp_ddns::NCR_UDP) {
+        isc_throw(D2ClientError, "D2ClientConfig error: NCR Protocol: "
+                  << dhcp_ddns::ncrProtocolToString(ncr_protocol)
+                  << " is not supported. ("
+                  << getPosition("ncr-protocol", client_config) << ")");
+    }
+
+    if (sender_ip.getFamily() != server_ip.getFamily()) {
+        isc_throw(D2ClientError,
+                  "D2ClientConfig error: 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")
+                  << " (" << getPosition("sender-ip", client_config) << ")");
+    }
+
+    if (server_ip == sender_ip && server_port == sender_port) {
+        isc_throw(D2ClientError,
+                  "D2ClientConfig error: server and sender cannot"
+                  " share the exact same IP address/port: "
+                  << server_ip.toText() << "/" << server_port
+                  << " (" << getPosition("sender-ip", client_config) << ")");
+    }
+
+    try {
         // Attempt to create the new client config.
         // Attempt to create the new client config.
-        local_client_config_.reset(new D2ClientConfig(enable_updates,
+        new_config.reset(new D2ClientConfig(enable_updates,
                                                       server_ip,
                                                       server_ip,
                                                       server_port,
                                                       server_port,
                                                       sender_ip,
                                                       sender_ip,
@@ -1367,49 +1456,50 @@ D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
         isc_throw(DhcpConfigError, ex.what() << " ("
         isc_throw(DhcpConfigError, ex.what() << " ("
                   << client_config->getPosition() << ")");
                   << client_config->getPosition() << ")");
     }
     }
+
+    return(new_config);
 }
 }
 
 
-isc::dhcp::ParserPtr
-D2ClientConfigParser::createConfigParser(const std::string& config_id) {
-    DhcpConfigParser* parser = NULL;
-    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) ||
-        (config_id.compare("replace-client-name") == 0)) {
-        parser = new StringParser(config_id, string_values_);
-    } else if ((config_id.compare("enable-updates") == 0) ||
-        (config_id.compare("always-include-fqdn") == 0) ||
-        (config_id.compare("allow-client-update") == 0) ||
-        (config_id.compare("override-no-update") == 0) ||
-        (config_id.compare("override-client-update") == 0)) {
-        parser = new BooleanParser(config_id, boolean_values_);
-    } else {
-        isc_throw(NotImplemented,
-            "parser error: D2ClientConfig parameter not supported: "
-            << config_id);
+bool
+D2ClientConfigParser::isShortCutDisabled(isc::data::ConstElementPtr d2_config) {
+    if (!d2_config->contains("enable-updates")) {
+        isc_throw(DhcpConfigError,
+                  "Mandatory parameter 'enable-updates' missing ("
+                  << d2_config->getPosition() << ")");
     }
     }
-
-    return (isc::dhcp::ParserPtr(parser));
+    ConstElementPtr enable = d2_config->get("enable-updates");
+    if (enable->getType() != Element::boolean) {
+        isc_throw(DhcpConfigError,
+                  "invalid value type specified for parameter"
+                  " 'enable-updates' (" << enable->getPosition() << ")");
+    }
+    return (!enable->boolValue() && (d2_config->mapValue().size() == 1));
 }
 }
 
 
-void
-D2ClientConfigParser::commit() {
-    // @todo if local_client_config_ is empty then shutdown the listener...
-    // @todo Should this also attempt to start a listener?
-    // In keeping with Interface, Subnet, and Hooks parsers, then this
-    // should initialize the listener.  Failure to init it, should cause
-    // rollback.  This gets sticky, because who owns the listener instance?
-    // Does CfgMgr maintain it or does the server class?  If the latter
-    // how do we get that value here?
-    // I'm thinkikng D2ClientConfig could contain the listener instance
-    CfgMgr::instance().setD2ClientConfig(local_client_config_);
+/// @brief This table defines default values for D2 client configuration
+const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
+    // enable-updates is unconditionally required
+    { "server-ip", Element::string, "127.0.0.1" },
+    { "server-port", Element::integer, "53001" },
+    // default sender-ip depends on server-ip family, so we leave default blank
+    // parser knows to use the appropriate ZERO address based on server-ip
+    { "sender-ip", Element::string, "" },
+    { "sender-port", Element::integer, "0" },
+    { "max-queue-size", Element::integer, "1024" },
+    { "ncr-protocol", Element::string, "UDP" },
+    { "ncr-format", Element::string, "JSON" },
+    { "always-include-fqdn", Element::boolean, "false" },
+    { "override-no-update", Element::boolean, "false" },
+    { "override-client-update", Element::boolean, "false" },
+    { "replace-client-name", Element::string, "never" },
+    { "generated-prefix", Element::string, "myhost" }
+    // qualifying-suffix has no default
+};
+
+size_t
+D2ClientConfigParser::setAllDefaults(isc::data::ConstElementPtr d2_config) {
+    ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);
+    return (SimpleParser::setDefaults(mutable_d2, D2_CLIENT_CONFIG_DEFAULTS));
 }
 }
 
 
 };  // namespace dhcp
 };  // namespace dhcp

+ 29 - 45
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -987,31 +987,14 @@ protected:
 /// @brief Parser for  D2ClientConfig
 /// @brief Parser for  D2ClientConfig
 ///
 ///
 /// This class parses the configuration element "dhcp-ddns" common to the
 /// This class parses the configuration element "dhcp-ddns" common to the
-/// spec files for both dhcp4 and dhcp6. It creates an instance of a
+/// config files for both dhcp4 and dhcp6. It creates an instance of a
 /// D2ClientConfig.
 /// D2ClientConfig.
-class D2ClientConfigParser : public  isc::dhcp::DhcpConfigParser {
+class D2ClientConfigParser : public  isc::data::SimpleParser {
 public:
 public:
-    /// @brief Constructor
-    ///
-    /// @param entry_name is an arbitrary label assigned to this configuration
-    /// definition.
-    D2ClientConfigParser(const std::string& entry_name);
-
-    /// @brief Destructor
-    virtual ~D2ClientConfigParser();
 
 
-    /// @brief Performs the parsing of the given dhcp-ddns element.
-    ///
-    /// The results of the parsing are retained internally for use during
-    /// commit.
-    /// @todo This parser supplies hard-coded default values for all
-    /// optional parameters.  This should be changed once a new plan
-    /// for configuration is determined.
+    /// @brief Parses a given dhcp-ddns element into D2ClientConfig.
     ///
     ///
     /// @param client_config is the "dhcp-ddns" configuration to parse
     /// @param client_config is the "dhcp-ddns" configuration to parse
-    virtual void build(isc::data::ConstElementPtr client_config);
-
-    /// @brief Creates a parser for the given "dhcp-ddns" member element id.
     ///
     ///
     /// The elements currently supported are (see isc::dhcp::D2ClientConfig
     /// The elements currently supported are (see isc::dhcp::D2ClientConfig
     /// for details on each):
     /// for details on each):
@@ -1019,9 +1002,11 @@ public:
     /// -# qualifying-suffix
     /// -# qualifying-suffix
     /// -# server-ip
     /// -# server-ip
     /// -# server-port
     /// -# server-port
+    /// -# sender-ip
+    /// -# sender-port
+    /// -# max-queue-size
     /// -# ncr-protocol
     /// -# ncr-protocol
     /// -# ncr-format
     /// -# ncr-format
-    /// -# remove-on-renew
     /// -# always-include-fqdn
     /// -# always-include-fqdn
     /// -# allow-client-update
     /// -# allow-client-update
     /// -# override-no-update
     /// -# override-no-update
@@ -1029,33 +1014,32 @@ public:
     /// -# replace-client-name
     /// -# replace-client-name
     /// -# generated-prefix
     /// -# generated-prefix
     ///
     ///
-    /// @param config_id is the "item_name" for a specific member element of
-    /// the "dns_server" specification.
-    ///
-    /// @return returns a pointer to newly created parser.
-    virtual isc::dhcp::ParserPtr createConfigParser(const std::string&
-                                                    config_id);
+    /// @return returns a pointer to newly created D2ClientConfig.
+    D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg);
 
 
-    /// @brief Instantiates a D2ClientConfig from internal data values
-    /// passes to CfgMgr singleton.
-    virtual void commit();
-
-private:
-    /// @brief Arbitrary label assigned to this parser instance.
-    /// Primarily used for diagnostics.
-    std::string entry_name_;
-
-    /// Storage for subnet-specific boolean values.
-    BooleanStoragePtr boolean_values_;
-
-    /// Storage for subnet-specific integer values.
-    Uint32StoragePtr uint32_values_;
+    /// @brief Check the short cut disabled updates condition
+    ///
+    /// The condition is that the d2 client configuration is
+    /// reduced to "enable-updates": false
+    ///
+    /// @param d2_config d2 client configuration
+    /// @return true if and only if the condition matches.
+    /// @throw DhcpConfigError if enable-updates is not present or
+    /// is not a boolean
+    static bool isShortCutDisabled(isc::data::ConstElementPtr d2_config);
 
 
-    /// Storage for subnet-specific string values.
-    StringStoragePtr string_values_;
+    /// @brief Defaults for the D2 client configuration.
+    static const isc::data::SimpleDefaults D2_CLIENT_CONFIG_DEFAULTS;
 
 
-    /// @brief Pointer to temporary local instance created during build.
-    D2ClientConfigPtr local_client_config_ ;
+    /// @brief Sets all defaults for D2 client configuration.
+    ///
+    /// This method sets defaults value. It must not be called
+    /// before the short cut disabled updates condition was checked.
+    ///
+    /// @param d2_config d2 client configuration (will be const cast
+    //  to ElementPtr)
+    /// @return number of parameters inserted
+    static size_t setAllDefaults(isc::data::ConstElementPtr d2_config);
 };
 };
 
 
 // Pointers to various parser objects.
 // Pointers to various parser objects.

+ 10 - 6
src/lib/dhcpsrv/srv_config.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -29,7 +29,8 @@ SrvConfig::SrvConfig()
       cfg_host_operations4_(CfgHostOperations::createConfig4()),
       cfg_host_operations4_(CfgHostOperations::createConfig4()),
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       class_dictionary_(new ClientClassDictionary()),
       class_dictionary_(new ClientClassDictionary()),
-      decline_timer_(0), dhcp4o6_port_(0) {
+      decline_timer_(0), dhcp4o6_port_(0),
+      d2_client_config_(new D2ClientConfig()) {
 }
 }
 
 
 SrvConfig::SrvConfig(const uint32_t sequence)
 SrvConfig::SrvConfig(const uint32_t sequence)
@@ -42,7 +43,8 @@ SrvConfig::SrvConfig(const uint32_t sequence)
       cfg_host_operations4_(CfgHostOperations::createConfig4()),
       cfg_host_operations4_(CfgHostOperations::createConfig4()),
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       class_dictionary_(new ClientClassDictionary()),
       class_dictionary_(new ClientClassDictionary()),
-      decline_timer_(0), dhcp4o6_port_(0) {
+      decline_timer_(0), dhcp4o6_port_(0),
+      d2_client_config_(new D2ClientConfig()) {
 }
 }
 
 
 std::string
 std::string
@@ -70,7 +72,7 @@ SrvConfig::getConfigSummary(const uint32_t selection) const {
     }
     }
 
 
     if ((selection & CFGSEL_DDNS) == CFGSEL_DDNS) {
     if ((selection & CFGSEL_DDNS) == CFGSEL_DDNS) {
-        bool ddns_enabled = CfgMgr::instance().ddnsEnabled();
+        bool ddns_enabled = getD2ClientConfig()->getEnableUpdates();
         s << "DDNS: " << (ddns_enabled ? "enabled" : "disabled") << "; ";
         s << "DDNS: " << (ddns_enabled ? "enabled" : "disabled") << "; ";
     }
     }
 
 
@@ -106,7 +108,8 @@ SrvConfig::copy(SrvConfig& new_config) const {
     cfg_option_->copyTo(*new_config.cfg_option_);
     cfg_option_->copyTo(*new_config.cfg_option_);
     // Replace the client class dictionary
     // Replace the client class dictionary
     new_config.class_dictionary_.reset(new ClientClassDictionary(*class_dictionary_));
     new_config.class_dictionary_.reset(new ClientClassDictionary(*class_dictionary_));
-
+    // Replace the D2 client configuration
+    new_config.setD2ClientConfig(getD2ClientConfig());
 }
 }
 
 
 void
 void
@@ -151,7 +154,8 @@ SrvConfig::equals(const SrvConfig& other) const {
     return ((*cfg_iface_ == *other.cfg_iface_) &&
     return ((*cfg_iface_ == *other.cfg_iface_) &&
             (*cfg_option_def_ == *other.cfg_option_def_) &&
             (*cfg_option_def_ == *other.cfg_option_def_) &&
             (*cfg_option_ == *other.cfg_option_) &&
             (*cfg_option_ == *other.cfg_option_) &&
-            (*class_dictionary_ == *other.class_dictionary_));
+            (*class_dictionary_ == *other.class_dictionary_) &&
+            (*d2_client_config_ == *other.d2_client_config_));
 }
 }
 
 
 void
 void

+ 21 - 2
src/lib/dhcpsrv/srv_config.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -20,6 +20,7 @@
 #include <dhcpsrv/cfg_subnets6.h>
 #include <dhcpsrv/cfg_subnets6.h>
 #include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/client_class_def.h>
 #include <dhcpsrv/client_class_def.h>
+#include <dhcpsrv/d2_client_cfg.h>
 #include <dhcpsrv/logging_info.h>
 #include <dhcpsrv/logging_info.h>
 #include <cc/data.h>
 #include <cc/data.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
@@ -481,12 +482,28 @@ public:
 
 
     /// @brief Returns DHCP4o6 IPC port
     /// @brief Returns DHCP4o6 IPC port
     ///
     ///
-    /// See @ref setDhcp4o6Port or brief discussion.                         
+    /// See @ref setDhcp4o6Port for brief discussion.
     /// @return value of DHCP4o6 IPC port
     /// @return value of DHCP4o6 IPC port
     uint32_t getDhcp4o6Port() {
     uint32_t getDhcp4o6Port() {
         return (dhcp4o6_port_);
         return (dhcp4o6_port_);
     }
     }
 
 
+    /// @brief Returns pointer to the D2 client configuration
+    D2ClientConfigPtr getD2ClientConfig() {
+        return (d2_client_config_);
+    }
+
+    /// @brief Returns pointer to const D2 client configuration
+    const D2ClientConfigPtr getD2ClientConfig() const {
+        return (d2_client_config_);
+    }
+
+    /// @brief Sets the D2 client configuration
+    /// @param dictionary pointer to the new D2 client configuration
+    void setD2ClientConfig(const D2ClientConfigPtr& d2_client_config) {
+        d2_client_config_ = d2_client_config;
+    }
+
 private:
 private:
 
 
     /// @brief Sequence number identifying the configuration.
     /// @brief Sequence number identifying the configuration.
@@ -570,6 +587,8 @@ private:
     /// DHCPv4-over-DHCPv6 uses a UDP socket for interserver communication,
     /// DHCPv4-over-DHCPv6 uses a UDP socket for interserver communication,
     /// this socket is bound and connected to this port and port + 1
     /// this socket is bound and connected to this port and port + 1
     uint32_t dhcp4o6_port_;
     uint32_t dhcp4o6_port_;
+
+    D2ClientConfigPtr d2_client_config_;
 };
 };
 
 
 /// @name Pointers to the @c SrvConfig object.
 /// @name Pointers to the @c SrvConfig object.

+ 55 - 22
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -349,9 +349,6 @@ public:
             return (answer);
             return (answer);
         }
         }
 
 
-        // option parsing must be done last, so save it if we hit if first
-        ParserPtr option_parser;
-
         ConfigPair config_pair;
         ConfigPair config_pair;
         try {
         try {
             // Iterate over the config elements.
             // Iterate over the config elements.
@@ -361,17 +358,18 @@ public:
 
 
                 // These are the simple parsers. No need to go through
                 // These are the simple parsers. No need to go through
                 // the ParserPtr hooplas with them.
                 // the ParserPtr hooplas with them.
-                if ( (config_pair.first == "option-data") ||
-                     (config_pair.first == "option-def")) {
+                if ((config_pair.first == "option-data") ||
+                    (config_pair.first == "option-def") ||
+                    (config_pair.first == "dhcp-ddns")) {
                     continue;
                     continue;
                 }
                 }
 
 
                 // We also don't care about the default values that may be been
                 // We also don't care about the default values that may be been
                 // inserted
                 // inserted
-                if ( (config_pair.first == "preferred-lifetime") ||
-                     (config_pair.first == "valid-lifetime") ||
-                     (config_pair.first == "renew-timer") ||
-                     (config_pair.first == "rebind-timer")) {
+                if ((config_pair.first == "preferred-lifetime") ||
+                    (config_pair.first == "valid-lifetime") ||
+                    (config_pair.first == "renew-timer") ||
+                    (config_pair.first == "rebind-timer")) {
                     continue;
                     continue;
                 }
                 }
 
 
@@ -388,14 +386,8 @@ public:
 
 
                 // Create the parser based on element name.
                 // Create the parser based on element name.
                 ParserPtr parser(createConfigParser(config_pair.first));
                 ParserPtr parser(createConfigParser(config_pair.first));
-                // Options must be parsed last
-                if (config_pair.first == "option-data") {
-                    option_parser = parser;
-                } else {
-                    // Anything else  we can call build straight away.
-                    parser->build(config_pair.second);
-                    parser->commit();
-                }
+                parser->build(config_pair.second);
+                parser->commit();
             }
             }
 
 
             int family = parser_context_->universe_ == Option::V4
             int family = parser_context_->universe_ == Option::V4
@@ -421,6 +413,16 @@ public:
                 option_list_parser.parse(cfg_option, option_config->second);
                 option_list_parser.parse(cfg_option, option_config->second);
             }
             }
 
 
+            // The dhcp-ddns parser is the next one to be run.
+            std::map<std::string, ConstElementPtr>::const_iterator
+                                d2_client_config = values_map.find("dhcp-ddns");
+            if (d2_client_config != values_map.end()) {
+                // Used to be done by parser commit
+                D2ClientConfigParser parser;
+                D2ClientConfigPtr cfg = parser.parse(d2_client_config->second);
+                CfgMgr::instance().setD2ClientConfig(cfg);
+            }
+
             // Everything was fine. Configuration is successful.
             // Everything was fine. Configuration is successful.
             answer = isc::config::createAnswer(0, "Configuration committed.");
             answer = isc::config::createAnswer(0, "Configuration committed.");
         } catch (const isc::Exception& ex) {
         } catch (const isc::Exception& ex) {
@@ -452,8 +454,10 @@ public:
         ParserPtr parser;
         ParserPtr parser;
         // option-data and option-def converted to SimpleParser, so they
         // option-data and option-def converted to SimpleParser, so they
         // are no longer here.
         // are no longer here.
-        if (config_id.compare("dhcp-ddns") == 0) {
-            parser.reset(new D2ClientConfigParser(config_id));
+        if (config_id.compare("hooks-libraries") == 0) {
+            parser.reset(new HooksLibrariesParser(config_id));
+            hooks_libraries_parser_ =
+                boost::dynamic_pointer_cast<HooksLibrariesParser>(parser);
         } else {
         } else {
             isc_throw(NotImplemented,
             isc_throw(NotImplemented,
                 "Parser error: configuration parameter not supported: "
                 "Parser error: configuration parameter not supported: "
@@ -507,6 +511,10 @@ public:
     /// src/bin/dhcp{4,6}, the most straightforward way is to simply copy the
     /// src/bin/dhcp{4,6}, the most straightforward way is to simply copy the
     /// minimum code here. Hence this method.
     /// minimum code here. Hence this method.
     ///
     ///
+    /// @todo - TKM, I think this is fairly hideous and we should figure out a
+    /// a way to not have to replicate in this fashion.  It may be minimum code
+    /// now, but it won't be fairly soon.
+    ///
     /// @param config configuration structure to be filled with default values
     /// @param config configuration structure to be filled with default values
     /// @param v6 true = DHCPv6, false = DHCPv4
     /// @param v6 true = DHCPv6, false = DHCPv4
     void setAllDefaults(ElementPtr config, bool v6) {
     void setAllDefaults(ElementPtr config, bool v6) {
@@ -555,6 +563,13 @@ public:
             setAllDefaults(config, GLOBAL6_DEFAULTS, OPTION4_DEFAULTS,
             setAllDefaults(config, GLOBAL6_DEFAULTS, OPTION4_DEFAULTS,
                            OPTION4_DEF_DEFAULTS);
                            OPTION4_DEF_DEFAULTS);
         }
         }
+
+        /// D2 client configuration code is in this library
+        ConstElementPtr d2_client = config->get("dhcp-ddns");
+        if (d2_client &&
+            !D2ClientConfigParser::isShortCutDisabled(d2_client)) {
+            D2ClientConfigParser::setAllDefaults(d2_client);
+        }
     }
     }
 
 
     /// @brief Convenience method for parsing a configuration
     /// @brief Convenience method for parsing a configuration
@@ -580,6 +595,7 @@ public:
             // If error was reported, the error string should contain
             // If error was reported, the error string should contain
             // position of the data element which caused failure.
             // position of the data element which caused failure.
             if (rcode_ != 0) {
             if (rcode_ != 0) {
+                std::cout << "Error text:" << error_text_ << std::endl;
                 EXPECT_TRUE(errorContainsPosition(status, "<string>"));
                 EXPECT_TRUE(errorContainsPosition(status, "<string>"));
             }
             }
         }
         }
@@ -852,7 +868,6 @@ TEST_F(ParseConfigTest, escapedOptionDataTest) {
         "    \"data\": \"\\\\SMSBoot\\\\x64\\\\wdsnbp.com\""
         "    \"data\": \"\\\\SMSBoot\\\\x64\\\\wdsnbp.com\""
         " } ]"
         " } ]"
         "}";
         "}";
-    std::cout << config << std::endl;
 
 
     // Verify that the configuration string parses.
     // Verify that the configuration string parses.
     int rcode = parseConfiguration(config);
     int rcode = parseConfiguration(config);
@@ -1858,12 +1873,30 @@ TEST_F(ParseConfigTest, parserDefaultsD2Config) {
 
 
 /// @brief Check various invalid D2 client configurations.
 /// @brief Check various invalid D2 client configurations.
 TEST_F(ParseConfigTest, invalidD2Config) {
 TEST_F(ParseConfigTest, invalidD2Config) {
-    std::string invalid_configs[] = {
+    std::string invalid_shortcuts[] = {
         // Must supply at least enable-updates
         // Must supply at least enable-updates
         "{ \"dhcp-ddns\" :"
         "{ \"dhcp-ddns\" :"
         "    {"
         "    {"
         "    }"
         "    }"
         "}",
         "}",
+        // Enable-updates must be a boolean
+        "{ \"dhcp-ddns\" :"
+        "    {"
+        "     \"enable-updates\" : 0"
+        "    }"
+        "}",
+        // stop
+        ""
+    };
+    int i = 0;
+    while (!invalid_shortcuts[i].empty()) {
+        // Verify that the configuration string parsing throws
+        EXPECT_THROW(parseConfiguration(invalid_shortcuts[i]),
+                     DhcpConfigError);
+        i++;
+    }
+
+    std::string invalid_configs[] = {
         // Must supply qualifying-suffix when updates are enabled
         // Must supply qualifying-suffix when updates are enabled
         "{ \"dhcp-ddns\" :"
         "{ \"dhcp-ddns\" :"
         "    {"
         "    {"
@@ -2018,7 +2051,7 @@ TEST_F(ParseConfigTest, invalidD2Config) {
     // Iterate through the invalid configuration strings, attempting to
     // Iterate through the invalid configuration strings, attempting to
     // parse each one.  They should fail to parse, but fail gracefully.
     // parse each one.  They should fail to parse, but fail gracefully.
     D2ClientConfigPtr current_config;
     D2ClientConfigPtr current_config;
-    int i = 0;
+    i = 0;
     while (!invalid_configs[i].empty()) {
     while (!invalid_configs[i].empty()) {
         // Verify that the configuration string parses without throwing.
         // Verify that the configuration string parses without throwing.
         int rcode = parseConfiguration(invalid_configs[i]);
         int rcode = parseConfiguration(invalid_configs[i]);

+ 4 - 3
src/lib/dhcpsrv/tests/srv_config_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -141,8 +141,9 @@ SrvConfigTest::addSubnet6(const unsigned int index) {
 
 
 void
 void
 SrvConfigTest::enableDDNS(const bool enable) {
 SrvConfigTest::enableDDNS(const bool enable) {
-    // D2 configuration should always be non-NULL.
-    CfgMgr::instance().getD2ClientConfig()->enableUpdates(enable);
+    const D2ClientConfigPtr& d2_config = conf_.getD2ClientConfig();
+    ASSERT_TRUE(d2_config);
+    d2_config->enableUpdates(enable);
 }
 }
 
 
 // Check that by default there are no logging entries
 // Check that by default there are no logging entries