Parcourir la source

[master] Finishing merge of trac5097 (migrate pool config)

Francis Dupont il y a 8 ans
Parent
commit
361561aab3

+ 5 - 1
doc/examples/kea6/hooks.json

@@ -24,7 +24,11 @@
 # Define a single subnet.
 # Define a single subnet.
   "subnet6": [
   "subnet6": [
     {
     {
-      "pools": [ { "pool": "2001:db8:1::/80" } ],
+      "pools": [
+        {
+          "pool": "2001:db8:1::/80",
+          "user-context": { "charging": true }
+        } ],
       "subnet": "2001:db8:1::/64",
       "subnet": "2001:db8:1::/64",
       "interface": "ethX"
       "interface": "ethX"
     }
     }

+ 15 - 0
doc/examples/kea6/multiple-options.json

@@ -39,6 +39,8 @@
 # addresses from the other pool, or the clients obtaining
 # addresses from the other pool, or the clients obtaining
 # stateless configuration will be assigned subnet specific value
 # stateless configuration will be assigned subnet specific value
 # of option 12, i.e. 2001:db8:1:0:ff00::1.
 # of option 12, i.e. 2001:db8:1:0:ff00::1.
+# For DHCPv6 subnets can have prefix delegation pools too so
+# a pd-pools with an option-data is defined too.
   "subnet6": [
   "subnet6": [
     {
     {
       "option-data": [
       "option-data": [
@@ -65,6 +67,19 @@
             "pool": "2001:db8:1::500 - 2001:db8:2::1000"
             "pool": "2001:db8:1::500 - 2001:db8:2::1000"
         }
         }
       ],
       ],
+      "pd-pools": [
+        {
+             "prefix": "2001:2b8:2::",
+             "prefix-len": 56,
+             "delegated-len": 64,
+             "option-data": [
+               {
+                   "code": 12,
+                   "data": "3001:cafe::12:"
+               }
+             ]
+         }
+      ],
       "subnet": "2001:db8:1::/64",
       "subnet": "2001:db8:1::/64",
       "interface": "ethX"
       "interface": "ethX"
     }
     }

Fichier diff supprimé car celui-ci est trop grand
+ 806 - 810
src/bin/dhcp4/dhcp4_lexer.cc


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

@@ -473,6 +473,15 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
     }
 }
 }
 
 
+\"user-context\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::POOLS:
+        return isc::dhcp::Dhcp4Parser::make_USER_CONTEXT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("user-context", driver.loc_);
+    }
+}
+
 \"subnet\" {
 \"subnet\" {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::SUBNET4:
     case isc::dhcp::Parser4Context::SUBNET4:

Fichier diff supprimé car celui-ci est trop grand
+ 1334 - 1313
src/bin/dhcp4/dhcp4_parser.cc


+ 120 - 125
src/bin/dhcp4/dhcp4_parser.h

@@ -306,7 +306,6 @@ namespace isc { namespace dhcp {
     {
     {
       // value
       // value
       // socket_type
       // socket_type
-      // db_type
       // ncr_protocol_value
       // ncr_protocol_value
       // replace_client_name_value
       // replace_client_name_value
       char dummy1[sizeof(ElementPtr)];
       char dummy1[sizeof(ElementPtr)];
@@ -366,65 +365,65 @@ namespace isc { namespace dhcp {
         TOKEN_LEASE_DATABASE = 276,
         TOKEN_LEASE_DATABASE = 276,
         TOKEN_HOSTS_DATABASE = 277,
         TOKEN_HOSTS_DATABASE = 277,
         TOKEN_TYPE = 278,
         TOKEN_TYPE = 278,
-        TOKEN_MEMFILE = 279,
-        TOKEN_MYSQL = 280,
-        TOKEN_POSTGRESQL = 281,
-        TOKEN_CQL = 282,
-        TOKEN_USER = 283,
-        TOKEN_PASSWORD = 284,
-        TOKEN_HOST = 285,
-        TOKEN_PERSIST = 286,
-        TOKEN_LFC_INTERVAL = 287,
-        TOKEN_READONLY = 288,
-        TOKEN_CONNECT_TIMEOUT = 289,
-        TOKEN_VALID_LIFETIME = 290,
-        TOKEN_RENEW_TIMER = 291,
-        TOKEN_REBIND_TIMER = 292,
-        TOKEN_DECLINE_PROBATION_PERIOD = 293,
-        TOKEN_SUBNET4 = 294,
-        TOKEN_SUBNET_4O6_INTERFACE = 295,
-        TOKEN_SUBNET_4O6_INTERFACE_ID = 296,
-        TOKEN_SUBNET_4O6_SUBNET = 297,
-        TOKEN_OPTION_DEF = 298,
-        TOKEN_OPTION_DATA = 299,
-        TOKEN_NAME = 300,
-        TOKEN_DATA = 301,
-        TOKEN_CODE = 302,
-        TOKEN_SPACE = 303,
-        TOKEN_CSV_FORMAT = 304,
-        TOKEN_RECORD_TYPES = 305,
-        TOKEN_ENCAPSULATE = 306,
-        TOKEN_ARRAY = 307,
-        TOKEN_POOLS = 308,
-        TOKEN_POOL = 309,
-        TOKEN_SUBNET = 310,
-        TOKEN_INTERFACE = 311,
-        TOKEN_INTERFACE_ID = 312,
-        TOKEN_ID = 313,
-        TOKEN_RAPID_COMMIT = 314,
-        TOKEN_RESERVATION_MODE = 315,
-        TOKEN_HOST_RESERVATION_IDENTIFIERS = 316,
-        TOKEN_CLIENT_CLASSES = 317,
-        TOKEN_TEST = 318,
-        TOKEN_CLIENT_CLASS = 319,
-        TOKEN_RESERVATIONS = 320,
-        TOKEN_DUID = 321,
-        TOKEN_HW_ADDRESS = 322,
-        TOKEN_CIRCUIT_ID = 323,
-        TOKEN_CLIENT_ID = 324,
-        TOKEN_HOSTNAME = 325,
-        TOKEN_RELAY = 326,
-        TOKEN_IP_ADDRESS = 327,
-        TOKEN_HOOKS_LIBRARIES = 328,
-        TOKEN_LIBRARY = 329,
-        TOKEN_PARAMETERS = 330,
-        TOKEN_EXPIRED_LEASES_PROCESSING = 331,
-        TOKEN_RECLAIM_TIMER_WAIT_TIME = 332,
-        TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 333,
-        TOKEN_HOLD_RECLAIMED_TIME = 334,
-        TOKEN_MAX_RECLAIM_LEASES = 335,
-        TOKEN_MAX_RECLAIM_TIME = 336,
-        TOKEN_UNWARNED_RECLAIM_CYCLES = 337,
+        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_DHCP4O6_PORT = 338,
         TOKEN_CONTROL_SOCKET = 339,
         TOKEN_CONTROL_SOCKET = 339,
         TOKEN_SOCKET_TYPE = 340,
         TOKEN_SOCKET_TYPE = 340,
@@ -678,22 +677,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MEMFILE (const location_type& l);
-
-    static inline
-    symbol_type
-    make_MYSQL (const location_type& l);
-
-    static inline
-    symbol_type
-    make_POSTGRESQL (const location_type& l);
-
-    static inline
-    symbol_type
-    make_CQL (const location_type& l);
-
-    static inline
-    symbol_type
     make_USER (const location_type& l);
     make_USER (const location_type& l);
 
 
     static inline
     static inline
@@ -718,10 +701,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_CONNECT_TIMEOUT (const location_type& l);
-
-    static inline
-    symbol_type
     make_VALID_LIFETIME (const location_type& l);
     make_VALID_LIFETIME (const location_type& l);
 
 
     static inline
     static inline
@@ -914,6 +893,26 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
+    make_SERVER_ID (const location_type& l);
+
+    static inline
+    symbol_type
+    make_IDENTIFIER (const location_type& l);
+
+    static inline
+    symbol_type
+    make_HTYPE (const location_type& l);
+
+    static inline
+    symbol_type
+    make_TIME (const location_type& l);
+
+    static inline
+    symbol_type
+    make_ENTERPRISE_ID (const location_type& l);
+
+    static inline
+    symbol_type
     make_DHCP4O6_PORT (const location_type& l);
     make_DHCP4O6_PORT (const location_type& l);
 
 
     static inline
     static inline
@@ -1313,8 +1312,8 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 713,     ///< Last index in yytable_.
-      yynnts_ = 299,  ///< Number of nonterminal symbols.
+      yylast_ = 732,     ///< Last index in yytable_.
+      yynnts_ = 305,  ///< Number of nonterminal symbols.
       yyfinal_ = 24, ///< Termination state number.
       yyfinal_ = 24, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
@@ -1410,9 +1409,8 @@ namespace isc { namespace dhcp {
     {
     {
       case 145: // value
       case 145: // value
       case 186: // socket_type
       case 186: // socket_type
-      case 195: // db_type
-      case 393: // ncr_protocol_value
-      case 402: // replace_client_name_value
+      case 399: // ncr_protocol_value
+      case 408: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
@@ -1451,9 +1449,8 @@ namespace isc { namespace dhcp {
     {
     {
       case 145: // value
       case 145: // value
       case 186: // socket_type
       case 186: // socket_type
-      case 195: // db_type
-      case 393: // ncr_protocol_value
-      case 402: // replace_client_name_value
+      case 399: // ncr_protocol_value
+      case 408: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
@@ -1551,9 +1548,8 @@ namespace isc { namespace dhcp {
     {
     {
       case 145: // value
       case 145: // value
       case 186: // socket_type
       case 186: // socket_type
-      case 195: // db_type
-      case 393: // ncr_protocol_value
-      case 402: // replace_client_name_value
+      case 399: // ncr_protocol_value
+      case 408: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
@@ -1598,9 +1594,8 @@ namespace isc { namespace dhcp {
     {
     {
       case 145: // value
       case 145: // value
       case 186: // socket_type
       case 186: // socket_type
-      case 195: // db_type
-      case 393: // ncr_protocol_value
-      case 402: // replace_client_name_value
+      case 399: // ncr_protocol_value
+      case 408: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
@@ -1826,30 +1821,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_MEMFILE (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_MEMFILE, l);
-  }
-
-  Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_MYSQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_MYSQL, l);
-  }
-
-  Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_POSTGRESQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_POSTGRESQL, l);
-  }
-
-  Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_CQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_CQL, l);
-  }
-
-  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_USER (const location_type& l)
   Dhcp4Parser::make_USER (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_USER, l);
     return symbol_type (token::TOKEN_USER, l);
@@ -1886,12 +1857,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_CONNECT_TIMEOUT (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_CONNECT_TIMEOUT, l);
-  }
-
-  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_VALID_LIFETIME (const location_type& l)
   Dhcp4Parser::make_VALID_LIFETIME (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_VALID_LIFETIME, l);
     return symbol_type (token::TOKEN_VALID_LIFETIME, l);
@@ -2180,6 +2145,36 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_SERVER_ID (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SERVER_ID, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_IDENTIFIER (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_IDENTIFIER, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_HTYPE (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_HTYPE, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_TIME (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_TIME, l);
+  }
+
+  Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_ENTERPRISE_ID (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ENTERPRISE_ID, l);
+  }
+
+  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_DHCP4O6_PORT (const location_type& l)
   Dhcp4Parser::make_DHCP4O6_PORT (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
     return symbol_type (token::TOKEN_DHCP4O6_PORT, l);
@@ -2476,7 +2471,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 2480 "dhcp4_parser.h" // lalr1.cc:377
+#line 2475 "dhcp4_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 12 - 0
src/bin/dhcp4/dhcp4_parser.yy

@@ -98,6 +98,7 @@ using namespace std;
 
 
   POOLS "pools"
   POOLS "pools"
   POOL "pool"
   POOL "pool"
+  USER_CONTEXT "user-context"
 
 
   SUBNET "subnet"
   SUBNET "subnet"
   INTERFACE "interface"
   INTERFACE "interface"
@@ -194,6 +195,7 @@ using namespace std;
 %token <bool> BOOLEAN "boolean"
 %token <bool> BOOLEAN "boolean"
 
 
 %type <ElementPtr> value
 %type <ElementPtr> value
+%type <ElementPtr> map_value
 %type <ElementPtr> socket_type
 %type <ElementPtr> socket_type
 %type <ElementPtr> db_type
 %type <ElementPtr> db_type
 %type <ElementPtr> ncr_protocol_value
 %type <ElementPtr> ncr_protocol_value
@@ -251,6 +253,8 @@ map2: LCURLY_BRACKET {
     // for it.
     // for it.
 };
 };
 
 
+map_value: map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); };
+
 // Assignments rule
 // Assignments rule
 map_content: %empty // empty map
 map_content: %empty // empty map
            | not_empty_map
            | not_empty_map
@@ -1141,6 +1145,7 @@ pool_params: pool_param
 
 
 pool_param: pool_entry
 pool_param: pool_entry
           | option_data_list
           | option_data_list
+          | user_context
           | unknown_map_entry
           | unknown_map_entry
           ;
           ;
 
 
@@ -1152,6 +1157,13 @@ pool_entry: POOL {
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+user_context: USER_CONTEXT {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON map_value {
+    ctx.stack_.back()->set("user-context", $4);
+    ctx.leave();
+};
+
 // --- end of pools definition -------------------------------
 // --- end of pools definition -------------------------------
 
 
 // --- reservations ------------------------------------------
 // --- reservations ------------------------------------------

+ 24 - 22
src/bin/dhcp4/json_config_parser.cc

@@ -54,18 +54,6 @@ namespace {
 ///
 ///
 /// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
 /// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
 class Pool4Parser : public PoolParser {
 class Pool4Parser : public PoolParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param param_name name of the parameter. Note, it is passed through
-    /// but unused, parameter is currently always "Dhcp4/subnet4[X]/pool"
-    /// @param pools storage container in which to store the parsed pool
-    /// upon "commit"
-    Pool4Parser(const std::string& param_name,  PoolStoragePtr pools)
-        :PoolParser(param_name, pools, AF_INET) {
-    }
-
 protected:
 protected:
     /// @brief Creates a Pool4 object given a IPv4 prefix and the prefix length.
     /// @brief Creates a Pool4 object given a IPv4 prefix and the prefix length.
     ///
     ///
@@ -90,15 +78,23 @@ protected:
     }
     }
 };
 };
 
 
-class Pools4ListParser : public PoolsListParser {
+/// @brief Specialization of the pool list parser for DHCPv4
+class Pools4ListParser : PoolsListParser {
 public:
 public:
-    Pools4ListParser(const std::string& dummy, PoolStoragePtr pools)
-        :PoolsListParser(dummy, pools) {
-    }
 
 
-protected:
-    virtual ParserPtr poolParserMaker(PoolStoragePtr storage) {
-        return (ParserPtr(new Pool4Parser("pool", storage)));
+    /// @brief parses the actual structure
+    ///
+    /// This method parses the actual list of pools.
+    ///
+    /// @param pools storage container in which to store the parsed pool.
+    /// @param pools_list a list of pool structures
+    /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
+    void parse(PoolStoragePtr pools,
+               isc::data::ConstElementPtr pools_list) {
+        BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
+            Pool4Parser parser;
+            parser.parse(pools, pool, AF_INET);
+        }
     }
     }
 };
 };
 
 
@@ -123,6 +119,13 @@ public:
     ///
     ///
     /// @param subnet A new subnet being configured.
     /// @param subnet A new subnet being configured.
     void build(ConstElementPtr subnet) {
     void build(ConstElementPtr subnet) {
+        /// Parse Pools first.
+        ConstElementPtr pools = subnet->get("pools");
+        if (pools) {
+            Pools4ListParser parser;
+            parser.parse(pools_, pools);
+        }
+
         SubnetConfigParser::build(subnet);
         SubnetConfigParser::build(subnet);
 
 
         if (subnet_) {
         if (subnet_) {
@@ -186,9 +189,8 @@ protected:
                    (config_id.compare("next-server") == 0) ||
                    (config_id.compare("next-server") == 0) ||
                    (config_id.compare("reservation-mode") == 0)) {
                    (config_id.compare("reservation-mode") == 0)) {
             parser = new StringParser(config_id, string_values_);
             parser = new StringParser(config_id, string_values_);
-        } else if (config_id.compare("pools") == 0) {
-            parser = new Pools4ListParser(config_id, pools_);
-            // relay has been converted to SimpleParser already.
+        // pools has been converted to SimpleParser already.
+        // relay has been converted to SimpleParser already.
         // option-data has been converted to SimpleParser already.
         // option-data has been converted to SimpleParser already.
         } else if (config_id.compare("match-client-id") == 0) {
         } else if (config_id.compare("match-client-id") == 0) {
             parser = new BooleanParser(config_id, boolean_values_);
             parser = new BooleanParser(config_id, boolean_values_);

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

@@ -1,4 +1,4 @@
-// Generated 201701251401
+// Generated 201701120056
 // 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++

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

@@ -1,4 +1,4 @@
-// Generated 201701251401
+// Generated 201701120056
 // 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 201701251401
+// Generated 201701120056
 // 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++

+ 184 - 2
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2016 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
@@ -107,6 +107,28 @@ const char* PARSER_CONFIGS[] = {
     "        ],"
     "        ],"
     "        \"subnet\": \"192.0.2.0/24\""
     "        \"subnet\": \"192.0.2.0/24\""
     "     } ]"
     "     } ]"
+    "}",
+
+    // Configuration 3: one min-max pool with user context containing lw4over6 parameters
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [\"*\" ]"
+    "    },"
+    "    \"valid-lifetime\": 4000,"
+    "    \"rebind-timer\": 2000,"
+    "    \"renew-timer\": 1000,"
+    "    \"subnet4\": [ {"
+    "        \"pools\": [ "
+    "            { \"pool\":  \"192.0.2.0 - 192.0.2.15\","
+    "                \"user-context\": {"
+    "                    \"integer-param\": 42,"
+    "                    \"string-param\": \"Sagittarius\","
+    "                    \"bool-param\": true"
+    "                }"
+    "            }"
+    "        ],"
+    "        \"subnet\": \"192.0.2.0/24\""
+    "     } ]"
     "}"
     "}"
 };
 };
 
 
@@ -572,8 +594,9 @@ public:
     void getPool(const std::string& config, size_t subnet_index,
     void getPool(const std::string& config, size_t subnet_index,
                  size_t pool_index, PoolPtr& pool) {
                  size_t pool_index, PoolPtr& pool) {
         ConstElementPtr status;
         ConstElementPtr status;
-        ElementPtr json = Element::fromJSON(config);
+        ConstElementPtr json;
 
 
+        EXPECT_NO_THROW(json = parseDHCP4(config, true));
         EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
         EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
         ASSERT_TRUE(status);
         ASSERT_TRUE(status);
         checkResult(status, 0);
         checkResult(status, 0);
@@ -1443,6 +1466,132 @@ TEST_F(Dhcp4ParserTest, poolPrefixLen) {
     EXPECT_EQ(4000, subnet->getValid());
     EXPECT_EQ(4000, subnet->getValid());
 }
 }
 
 
+// Goal of this test is to verify if invalid pool definitions
+// return a location in the error message.
+TEST_F(Dhcp4ParserTest, badPools) {
+
+    // not a prefix
+    string config_bogus1 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo/28\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not a length
+    string config_bogus2 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.128/foo\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // invalid prefix length
+    string config_bogus3 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.128/100\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not a prefix nor a min-max
+    string config_bogus4 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not an address
+    string config_bogus5 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo - bar\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // min > max
+    string config_bogus6 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.200 - 192.0.2.100\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // out of range prefix length (new check)
+    string config_bogus7 = "{ " + genIfaceConfig() + "," +
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.128/1052\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ConstElementPtr json1;
+    ASSERT_NO_THROW(json1 = parseDHCP4(config_bogus1));
+    ConstElementPtr json2;
+    ASSERT_NO_THROW(json2 = parseDHCP4(config_bogus2));
+    ConstElementPtr json3;
+    ASSERT_NO_THROW(json3 = parseDHCP4(config_bogus3));
+    ConstElementPtr json4;
+    ASSERT_NO_THROW(json4 = parseDHCP4(config_bogus4));
+    ConstElementPtr json5;
+    ASSERT_NO_THROW(json5 = parseDHCP4(config_bogus5));
+    ConstElementPtr json6;
+    ASSERT_NO_THROW(json6 = parseDHCP4(config_bogus6));
+    ConstElementPtr json7;
+    ASSERT_NO_THROW(json7 = parseDHCP4(config_bogus7));
+
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json1));
+
+    // check if returned status is always a failure
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json2));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json4));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json5));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json6));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json7));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+}
+
 // The goal of this test is to check whether an option definition
 // The goal of this test is to check whether an option definition
 // that defines an option carrying an IPv4 address can be created.
 // that defines an option carrying an IPv4 address can be created.
 TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
 TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
@@ -4480,5 +4629,38 @@ TEST_F(Dhcp4ParserTest, poolUserContextData) {
     EXPECT_EQ(true, bool_value);
     EXPECT_EQ(true, bool_value);
 }
 }
 
 
+// Test verifies that it's possible to specify parameters in the user context
+// in the min-max address pool.
+TEST_F(Dhcp4ParserTest, pooMinMaxlUserContext) {
+    PoolPtr pool;
+    getPool(string(PARSER_CONFIGS[3]), 0, 0, pool);
+    ASSERT_TRUE(pool);
+    ConstElementPtr ctx = pool->getContext();
+    ASSERT_TRUE(ctx);
+
+    // The context should be of type map and contain 4 parameters.
+    EXPECT_EQ(Element::map, ctx->getType());
+    EXPECT_EQ(3, ctx->size());
+    ConstElementPtr int_param  = ctx->get("integer-param");
+    ConstElementPtr str_param  = ctx->get("string-param");
+    ConstElementPtr bool_param = ctx->get("bool-param");
+
+    ASSERT_TRUE(int_param);
+    ASSERT_EQ(Element::integer, int_param->getType());
+    int64_t int_value;
+    EXPECT_NO_THROW(int_param->getValue(int_value));
+    EXPECT_EQ(42L, int_value);
+
+    ASSERT_TRUE(str_param);
+    ASSERT_EQ(Element::string, str_param->getType());
+    EXPECT_EQ("Sagittarius", str_param->stringValue());
+
+    ASSERT_TRUE(bool_param);
+    bool bool_value;
+    ASSERT_EQ(Element::boolean, bool_param->getType());
+    EXPECT_NO_THROW(bool_param->getValue(bool_value));
+    EXPECT_EQ(true, bool_value);
+}
+
 
 
 }
 }

Fichier diff supprimé car celui-ci est trop grand
+ 816 - 900
src/bin/dhcp6/dhcp6_lexer.cc


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

@@ -739,6 +739,16 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
     }
 }
 }
 
 
+\"user-context\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::POOLS:
+    case isc::dhcp::Parser6Context::PD_POOLS:
+        return isc::dhcp::Dhcp6Parser::make_USER_CONTEXT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("user-context", driver.loc_);
+    }
+}
+
 \"subnet\" {
 \"subnet\" {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SUBNET6:

Fichier diff supprimé car celui-ci est trop grand
+ 1335 - 1386
src/bin/dhcp6/dhcp6_parser.cc


+ 158 - 219
src/bin/dhcp6/dhcp6_parser.h

@@ -305,7 +305,6 @@ namespace isc { namespace dhcp {
     union union_type
     union union_type
     {
     {
       // value
       // value
-      // db_type
       // duid_type
       // duid_type
       // ncr_protocol_value
       // ncr_protocol_value
       // replace_client_name_value
       // replace_client_name_value
@@ -358,130 +357,125 @@ namespace isc { namespace dhcp {
         TOKEN_LEASE_DATABASE = 268,
         TOKEN_LEASE_DATABASE = 268,
         TOKEN_HOSTS_DATABASE = 269,
         TOKEN_HOSTS_DATABASE = 269,
         TOKEN_TYPE = 270,
         TOKEN_TYPE = 270,
-        TOKEN_MEMFILE = 271,
-        TOKEN_MYSQL = 272,
-        TOKEN_POSTGRESQL = 273,
-        TOKEN_CQL = 274,
-        TOKEN_USER = 275,
-        TOKEN_PASSWORD = 276,
-        TOKEN_HOST = 277,
-        TOKEN_PERSIST = 278,
-        TOKEN_LFC_INTERVAL = 279,
-        TOKEN_READONLY = 280,
-        TOKEN_CONNECT_TIMEOUT = 281,
-        TOKEN_PREFERRED_LIFETIME = 282,
-        TOKEN_VALID_LIFETIME = 283,
-        TOKEN_RENEW_TIMER = 284,
-        TOKEN_REBIND_TIMER = 285,
-        TOKEN_DECLINE_PROBATION_PERIOD = 286,
-        TOKEN_SUBNET6 = 287,
-        TOKEN_OPTION_DEF = 288,
-        TOKEN_OPTION_DATA = 289,
-        TOKEN_NAME = 290,
-        TOKEN_DATA = 291,
-        TOKEN_CODE = 292,
-        TOKEN_SPACE = 293,
-        TOKEN_CSV_FORMAT = 294,
-        TOKEN_RECORD_TYPES = 295,
-        TOKEN_ENCAPSULATE = 296,
-        TOKEN_ARRAY = 297,
-        TOKEN_POOLS = 298,
-        TOKEN_POOL = 299,
-        TOKEN_PD_POOLS = 300,
-        TOKEN_PREFIX = 301,
-        TOKEN_PREFIX_LEN = 302,
-        TOKEN_EXCLUDED_PREFIX = 303,
-        TOKEN_EXCLUDED_PREFIX_LEN = 304,
-        TOKEN_DELEGATED_LEN = 305,
-        TOKEN_SUBNET = 306,
-        TOKEN_INTERFACE = 307,
-        TOKEN_INTERFACE_ID = 308,
-        TOKEN_ID = 309,
-        TOKEN_RAPID_COMMIT = 310,
-        TOKEN_RESERVATION_MODE = 311,
-        TOKEN_MAC_SOURCES = 312,
-        TOKEN_RELAY_SUPPLIED_OPTIONS = 313,
-        TOKEN_HOST_RESERVATION_IDENTIFIERS = 314,
-        TOKEN_CLIENT_CLASSES = 315,
-        TOKEN_TEST = 316,
-        TOKEN_CLIENT_CLASS = 317,
-        TOKEN_RESERVATIONS = 318,
-        TOKEN_IP_ADDRESSES = 319,
-        TOKEN_PREFIXES = 320,
-        TOKEN_DUID = 321,
-        TOKEN_HW_ADDRESS = 322,
-        TOKEN_HOSTNAME = 323,
-        TOKEN_RELAY = 324,
-        TOKEN_IP_ADDRESS = 325,
-        TOKEN_HOOKS_LIBRARIES = 326,
-        TOKEN_LIBRARY = 327,
-        TOKEN_PARAMETERS = 328,
-        TOKEN_EXPIRED_LEASES_PROCESSING = 329,
-        TOKEN_RECLAIM_TIMER_WAIT_TIME = 330,
-        TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 331,
-        TOKEN_HOLD_RECLAIMED_TIME = 332,
-        TOKEN_MAX_RECLAIM_LEASES = 333,
-        TOKEN_MAX_RECLAIM_TIME = 334,
-        TOKEN_UNWARNED_RECLAIM_CYCLES = 335,
-        TOKEN_SERVER_ID = 336,
-        TOKEN_LLT = 337,
-        TOKEN_EN = 338,
-        TOKEN_LL = 339,
-        TOKEN_IDENTIFIER = 340,
-        TOKEN_HTYPE = 341,
-        TOKEN_TIME = 342,
-        TOKEN_ENTERPRISE_ID = 343,
-        TOKEN_DHCP4O6_PORT = 344,
-        TOKEN_CONTROL_SOCKET = 345,
-        TOKEN_SOCKET_TYPE = 346,
-        TOKEN_SOCKET_NAME = 347,
-        TOKEN_DHCP_DDNS = 348,
-        TOKEN_ENABLE_UPDATES = 349,
-        TOKEN_QUALIFYING_SUFFIX = 350,
-        TOKEN_SERVER_IP = 351,
-        TOKEN_SERVER_PORT = 352,
-        TOKEN_SENDER_IP = 353,
-        TOKEN_SENDER_PORT = 354,
-        TOKEN_MAX_QUEUE_SIZE = 355,
-        TOKEN_NCR_PROTOCOL = 356,
-        TOKEN_NCR_FORMAT = 357,
-        TOKEN_ALWAYS_INCLUDE_FQDN = 358,
-        TOKEN_ALLOW_CLIENT_UPDATE = 359,
-        TOKEN_OVERRIDE_NO_UPDATE = 360,
-        TOKEN_OVERRIDE_CLIENT_UPDATE = 361,
-        TOKEN_REPLACE_CLIENT_NAME = 362,
-        TOKEN_GENERATED_PREFIX = 363,
-        TOKEN_UDP = 364,
-        TOKEN_TCP = 365,
-        TOKEN_JSON = 366,
-        TOKEN_WHEN_PRESENT = 367,
-        TOKEN_NEVER = 368,
-        TOKEN_ALWAYS = 369,
-        TOKEN_WHEN_NOT_PRESENT = 370,
-        TOKEN_LOGGING = 371,
-        TOKEN_LOGGERS = 372,
-        TOKEN_OUTPUT_OPTIONS = 373,
-        TOKEN_OUTPUT = 374,
-        TOKEN_DEBUGLEVEL = 375,
-        TOKEN_SEVERITY = 376,
-        TOKEN_DHCP4 = 377,
-        TOKEN_DHCPDDNS = 378,
-        TOKEN_TOPLEVEL_JSON = 379,
-        TOKEN_TOPLEVEL_DHCP6 = 380,
-        TOKEN_SUB_DHCP6 = 381,
-        TOKEN_SUB_INTERFACES6 = 382,
-        TOKEN_SUB_SUBNET6 = 383,
-        TOKEN_SUB_POOL6 = 384,
-        TOKEN_SUB_PD_POOL = 385,
-        TOKEN_SUB_RESERVATION = 386,
-        TOKEN_SUB_OPTION_DEF = 387,
-        TOKEN_SUB_OPTION_DATA = 388,
-        TOKEN_SUB_HOOKS_LIBRARY = 389,
-        TOKEN_SUB_DHCP_DDNS = 390,
-        TOKEN_STRING = 391,
-        TOKEN_INTEGER = 392,
-        TOKEN_FLOAT = 393,
-        TOKEN_BOOLEAN = 394
+        TOKEN_USER = 271,
+        TOKEN_PASSWORD = 272,
+        TOKEN_HOST = 273,
+        TOKEN_PERSIST = 274,
+        TOKEN_LFC_INTERVAL = 275,
+        TOKEN_READONLY = 276,
+        TOKEN_PREFERRED_LIFETIME = 277,
+        TOKEN_VALID_LIFETIME = 278,
+        TOKEN_RENEW_TIMER = 279,
+        TOKEN_REBIND_TIMER = 280,
+        TOKEN_DECLINE_PROBATION_PERIOD = 281,
+        TOKEN_SUBNET6 = 282,
+        TOKEN_OPTION_DEF = 283,
+        TOKEN_OPTION_DATA = 284,
+        TOKEN_NAME = 285,
+        TOKEN_DATA = 286,
+        TOKEN_CODE = 287,
+        TOKEN_SPACE = 288,
+        TOKEN_CSV_FORMAT = 289,
+        TOKEN_RECORD_TYPES = 290,
+        TOKEN_ENCAPSULATE = 291,
+        TOKEN_ARRAY = 292,
+        TOKEN_POOLS = 293,
+        TOKEN_POOL = 294,
+        TOKEN_PD_POOLS = 295,
+        TOKEN_PREFIX = 296,
+        TOKEN_PREFIX_LEN = 297,
+        TOKEN_EXCLUDED_PREFIX = 298,
+        TOKEN_EXCLUDED_PREFIX_LEN = 299,
+        TOKEN_DELEGATED_LEN = 300,
+        TOKEN_SUBNET = 301,
+        TOKEN_INTERFACE = 302,
+        TOKEN_INTERFACE_ID = 303,
+        TOKEN_ID = 304,
+        TOKEN_RAPID_COMMIT = 305,
+        TOKEN_RESERVATION_MODE = 306,
+        TOKEN_MAC_SOURCES = 307,
+        TOKEN_RELAY_SUPPLIED_OPTIONS = 308,
+        TOKEN_HOST_RESERVATION_IDENTIFIERS = 309,
+        TOKEN_CLIENT_CLASSES = 310,
+        TOKEN_TEST = 311,
+        TOKEN_CLIENT_CLASS = 312,
+        TOKEN_RESERVATIONS = 313,
+        TOKEN_IP_ADDRESSES = 314,
+        TOKEN_PREFIXES = 315,
+        TOKEN_DUID = 316,
+        TOKEN_HW_ADDRESS = 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_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_ENABLE_UPDATES = 344,
+        TOKEN_QUALIFYING_SUFFIX = 345,
+        TOKEN_SERVER_IP = 346,
+        TOKEN_SERVER_PORT = 347,
+        TOKEN_SENDER_IP = 348,
+        TOKEN_SENDER_PORT = 349,
+        TOKEN_MAX_QUEUE_SIZE = 350,
+        TOKEN_NCR_PROTOCOL = 351,
+        TOKEN_NCR_FORMAT = 352,
+        TOKEN_ALWAYS_INCLUDE_FQDN = 353,
+        TOKEN_ALLOW_CLIENT_UPDATE = 354,
+        TOKEN_OVERRIDE_NO_UPDATE = 355,
+        TOKEN_OVERRIDE_CLIENT_UPDATE = 356,
+        TOKEN_REPLACE_CLIENT_NAME = 357,
+        TOKEN_GENERATED_PREFIX = 358,
+        TOKEN_UDP = 359,
+        TOKEN_TCP = 360,
+        TOKEN_JSON = 361,
+        TOKEN_WHEN_PRESENT = 362,
+        TOKEN_NEVER = 363,
+        TOKEN_ALWAYS = 364,
+        TOKEN_WHEN_NOT_PRESENT = 365,
+        TOKEN_LOGGING = 366,
+        TOKEN_LOGGERS = 367,
+        TOKEN_OUTPUT_OPTIONS = 368,
+        TOKEN_OUTPUT = 369,
+        TOKEN_DEBUGLEVEL = 370,
+        TOKEN_SEVERITY = 371,
+        TOKEN_DHCP4 = 372,
+        TOKEN_DHCPDDNS = 373,
+        TOKEN_TOPLEVEL_JSON = 374,
+        TOKEN_TOPLEVEL_DHCP6 = 375,
+        TOKEN_SUB_DHCP6 = 376,
+        TOKEN_SUB_INTERFACES6 = 377,
+        TOKEN_SUB_SUBNET6 = 378,
+        TOKEN_SUB_POOL6 = 379,
+        TOKEN_SUB_PD_POOL = 380,
+        TOKEN_SUB_RESERVATION = 381,
+        TOKEN_SUB_OPTION_DEF = 382,
+        TOKEN_SUB_OPTION_DATA = 383,
+        TOKEN_SUB_HOOKS_LIBRARY = 384,
+        TOKEN_SUB_DHCP_DDNS = 385,
+        TOKEN_STRING = 386,
+        TOKEN_INTEGER = 387,
+        TOKEN_FLOAT = 388,
+        TOKEN_BOOLEAN = 389
       };
       };
     };
     };
 
 
@@ -654,22 +648,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_MEMFILE (const location_type& l);
-
-    static inline
-    symbol_type
-    make_MYSQL (const location_type& l);
-
-    static inline
-    symbol_type
-    make_POSTGRESQL (const location_type& l);
-
-    static inline
-    symbol_type
-    make_CQL (const location_type& l);
-
-    static inline
-    symbol_type
     make_USER (const location_type& l);
     make_USER (const location_type& l);
 
 
     static inline
     static inline
@@ -694,10 +672,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_CONNECT_TIMEOUT (const location_type& l);
-
-    static inline
-    symbol_type
     make_PREFERRED_LIFETIME (const location_type& l);
     make_PREFERRED_LIFETIME (const location_type& l);
 
 
     static inline
     static inline
@@ -1353,12 +1327,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 760,     ///< Last index in yytable_.
-      yynnts_ = 314,  ///< Number of nonterminal symbols.
+      yylast_ = 752,     ///< Last index in yytable_.
+      yynnts_ = 312,  ///< Number of nonterminal symbols.
       yyfinal_ = 26, ///< Termination state number.
       yyfinal_ = 26, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 140  ///< Number of tokens.
+      yyntokens_ = 135  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1413,10 +1387,9 @@ namespace isc { namespace dhcp {
       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,   112,   113,   114,
      105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
-     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
-     135,   136,   137,   138,   139
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134
     };
     };
-    const unsigned int user_token_number_max_ = 394;
+    const unsigned int user_token_number_max_ = 389;
     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_)
@@ -1449,27 +1422,26 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 154: // value
-      case 198: // db_type
-      case 383: // duid_type
-      case 416: // ncr_protocol_value
-      case 425: // replace_client_name_value
+      case 149: // value
+      case 376: // duid_type
+      case 409: // ncr_protocol_value
+      case 418: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 139: // "boolean"
+      case 134: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 138: // "floating point"
+      case 133: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 137: // "integer"
+      case 132: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 136: // "constant string"
+      case 131: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1490,27 +1462,26 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 154: // value
-      case 198: // db_type
-      case 383: // duid_type
-      case 416: // ncr_protocol_value
-      case 425: // replace_client_name_value
+      case 149: // value
+      case 376: // duid_type
+      case 409: // ncr_protocol_value
+      case 418: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 139: // "boolean"
+      case 134: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 138: // "floating point"
+      case 133: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 137: // "integer"
+      case 132: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 136: // "constant string"
+      case 131: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1590,27 +1561,26 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 154: // value
-      case 198: // db_type
-      case 383: // duid_type
-      case 416: // ncr_protocol_value
-      case 425: // replace_client_name_value
+      case 149: // value
+      case 376: // duid_type
+      case 409: // ncr_protocol_value
+      case 418: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 139: // "boolean"
+      case 134: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 138: // "floating point"
+      case 133: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 137: // "integer"
+      case 132: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 136: // "constant string"
+      case 131: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1637,27 +1607,26 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 154: // value
-      case 198: // db_type
-      case 383: // duid_type
-      case 416: // ncr_protocol_value
-      case 425: // replace_client_name_value
+      case 149: // value
+      case 376: // duid_type
+      case 409: // ncr_protocol_value
+      case 418: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 139: // "boolean"
+      case 134: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 138: // "floating point"
+      case 133: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 137: // "integer"
+      case 132: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 136: // "constant string"
+      case 131: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1729,7 +1698,7 @@ namespace isc { namespace dhcp {
      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,
      365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394
+     385,   386,   387,   388,   389
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -1819,30 +1788,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_MEMFILE (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_MEMFILE, l);
-  }
-
-  Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_MYSQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_MYSQL, l);
-  }
-
-  Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_POSTGRESQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_POSTGRESQL, l);
-  }
-
-  Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_CQL (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_CQL, l);
-  }
-
-  Dhcp6Parser::symbol_type
   Dhcp6Parser::make_USER (const location_type& l)
   Dhcp6Parser::make_USER (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_USER, l);
     return symbol_type (token::TOKEN_USER, l);
@@ -1879,12 +1824,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_CONNECT_TIMEOUT (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_CONNECT_TIMEOUT, l);
-  }
-
-  Dhcp6Parser::symbol_type
   Dhcp6Parser::make_PREFERRED_LIFETIME (const location_type& l)
   Dhcp6Parser::make_PREFERRED_LIFETIME (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_PREFERRED_LIFETIME, l);
     return symbol_type (token::TOKEN_PREFERRED_LIFETIME, l);
@@ -2565,7 +2504,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 2569 "dhcp6_parser.h" // lalr1.cc:377
+#line 2508 "dhcp6_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 13 - 0
src/bin/dhcp6/dhcp6_parser.yy

@@ -93,6 +93,7 @@ using namespace std;
   EXCLUDED_PREFIX "excluded-prefix"
   EXCLUDED_PREFIX "excluded-prefix"
   EXCLUDED_PREFIX_LEN "excluded-prefix-len"
   EXCLUDED_PREFIX_LEN "excluded-prefix-len"
   DELEGATED_LEN "delegated-len"
   DELEGATED_LEN "delegated-len"
+  USER_CONTEXT "user-context"
 
 
   SUBNET "subnet"
   SUBNET "subnet"
   INTERFACE "interface"
   INTERFACE "interface"
@@ -202,6 +203,7 @@ using namespace std;
 %token <bool> BOOLEAN "boolean"
 %token <bool> BOOLEAN "boolean"
 
 
 %type <ElementPtr> value
 %type <ElementPtr> value
+%type <ElementPtr> map_value
 %type <ElementPtr> db_type
 %type <ElementPtr> db_type
 %type <ElementPtr> duid_type
 %type <ElementPtr> duid_type
 %type <ElementPtr> ncr_protocol_value
 %type <ElementPtr> ncr_protocol_value
@@ -260,6 +262,8 @@ map2: LCURLY_BRACKET {
     // for it.
     // for it.
 };
 };
 
 
+map_value: map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); };
+
 // Assignments rule
 // Assignments rule
 map_content: %empty // empty map
 map_content: %empty // empty map
            | not_empty_map
            | not_empty_map
@@ -1122,6 +1126,7 @@ pool_params: pool_param
 
 
 pool_param: pool_entry
 pool_param: pool_entry
           | option_data_list
           | option_data_list
+          | user_context
           | unknown_map_entry
           | unknown_map_entry
           ;
           ;
 
 
@@ -1133,6 +1138,13 @@ pool_entry: POOL {
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+user_context: USER_CONTEXT {
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON map_value {
+    ctx.stack_.back()->set("user-context", $4);
+    ctx.leave();
+};
+
 // --- end of pools definition -------------------------------
 // --- end of pools definition -------------------------------
 
 
 // --- pd-pools ----------------------------------------------
 // --- pd-pools ----------------------------------------------
@@ -1182,6 +1194,7 @@ pd_pool_param: pd_prefix
              | option_data_list
              | option_data_list
              | excluded_prefix
              | excluded_prefix
              | excluded_prefix_len
              | excluded_prefix_len
+             | user_context
              | unknown_map_entry
              | unknown_map_entry
              ;
              ;
 
 

+ 105 - 140
src/bin/dhcp6/json_config_parser.cc

@@ -71,18 +71,6 @@ typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 ///
 ///
 /// It is useful for parsing Dhcp6/subnet6[X]/pool parameters.
 /// It is useful for parsing Dhcp6/subnet6[X]/pool parameters.
 class Pool6Parser : public PoolParser {
 class Pool6Parser : public PoolParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// @param param_name name of the parameter. Note, it is passed through
-    /// but unused, parameter is currently always "Dhcp6/subnet6[X]/pool"
-    /// @param pools storage container in which to store the parsed pool
-    /// upon "commit"
-    Pool6Parser(const std::string& param_name,  PoolStoragePtr pools)
-        :PoolParser(param_name, pools, AF_INET6) {
-    }
-
 protected:
 protected:
     /// @brief Creates a Pool6 object given a IPv6 prefix and the prefix length.
     /// @brief Creates a Pool6 object given a IPv6 prefix and the prefix length.
     ///
     ///
@@ -113,15 +101,23 @@ protected:
     }
     }
 };
 };
 
 
-class Pools6ListParser : public PoolsListParser {
+/// @brief Specialization of the pool list parser for DHCPv6
+class Pools6ListParser : PoolsListParser {
 public:
 public:
-    Pools6ListParser(const std::string& dummy, PoolStoragePtr pools)
-        :PoolsListParser(dummy, pools) {
-    }
 
 
-protected:
-    virtual ParserPtr poolParserMaker(PoolStoragePtr storage) {
-        return (ParserPtr(new Pool6Parser("pool", storage)));
+    /// @brief parses the actual structure
+    ///
+    /// This method parses the actual list of pools.
+    ///
+    /// @param pools storage container in which to store the parsed pool.
+    /// @param pools_list a list of pool structures
+    /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
+    void parse(PoolStoragePtr pools,
+               isc::data::ConstElementPtr pools_list) {
+        BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
+            Pool6Parser parser;
+            parser.parse(pools, pool, AF_INET6);
+        }
     }
     }
 };
 };
 
 
@@ -142,23 +138,12 @@ protected:
 /// }
 /// }
 /// @endcode
 /// @endcode
 ///
 ///
-class PdPoolParser : public DhcpConfigParser {
+class PdPoolParser : public isc::data::SimpleParser {
 public:
 public:
 
 
     /// @brief Constructor.
     /// @brief Constructor.
     ///
     ///
-    /// @param param_name name of the parameter. Note, it is passed through
-    /// but unused, parameter is currently always "Dhcp6/subnet6[X]/pool"
-    /// @param pools storage container in which to store the parsed pool
-    /// upon "commit"
-    PdPoolParser(const std::string&,  PoolStoragePtr pools)
-        : uint32_values_(new Uint32Storage()),
-          string_values_(new StringStorage()), pools_(pools),
-          options_(new CfgOption()) {
-        if (!pools_) {
-            isc_throw(isc::dhcp::DhcpConfigError,
-                      "PdPoolParser context storage may not be NULL");
-        }
+    PdPoolParser() : options_(new CfgOption()) {
     }
     }
 
 
     /// @brief Builds a prefix delegation pool from the given configuration
     /// @brief Builds a prefix delegation pool from the given configuration
@@ -166,57 +151,63 @@ public:
     /// This function parses configuration entries and creates an instance
     /// This function parses configuration entries and creates an instance
     /// of a dhcp::Pool6 configured for prefix delegation.
     /// of a dhcp::Pool6 configured for prefix delegation.
     ///
     ///
+    /// @param pools storage container in which to store the parsed pool.
     /// @param pd_pool_ pointer to an element that holds configuration entries
     /// @param pd_pool_ pointer to an element that holds configuration entries
     /// that define a prefix delegation pool.
     /// that define a prefix delegation pool.
     ///
     ///
     /// @throw DhcpConfigError if configuration parsing fails.
     /// @throw DhcpConfigError if configuration parsing fails.
-    virtual void build(ConstElementPtr pd_pool_) {
+  void parse(PoolStoragePtr pools,
+             ConstElementPtr pd_pool_) {
+        std::string addr_str;
+        std::string excluded_prefix_str = "::";
+        uint8_t prefix_len = 0;
+        uint8_t delegated_len = 0;
+        uint8_t excluded_prefix_len = 0;
+
         // Parse the elements that make up the option definition.
         // Parse the elements that make up the option definition.
         BOOST_FOREACH(ConfigPair param, pd_pool_->mapValue()) {
         BOOST_FOREACH(ConfigPair param, pd_pool_->mapValue()) {
             std::string entry(param.first);
             std::string entry(param.first);
-            ParserPtr parser;
-            if (entry == "prefix" || entry =="excluded-prefix") {
-                StringParserPtr str_parser(new StringParser(entry,
-                                                            string_values_));
-                parser = str_parser;
-            } else if (entry == "prefix-len" || entry == "delegated-len" ||
-                       entry == "excluded-prefix-len") {
-                Uint32ParserPtr code_parser(new Uint32Parser(entry,
-                                                             uint32_values_));
-                parser = code_parser;
-            } else if (entry == "option-data") {
-                OptionDataListParser opts_parser(AF_INET6);
-                opts_parser.parse(options_, param.second);
-
-                // OptionDataListParser is converted to SimpleParser already,
-                // no need to go through build/commit phases.
-                continue;
-            } else if (entry == "user-context") {
-                user_context_ = param.second;
-                continue; // no parser to remember, simply store the value
-            } else {
-                isc_throw(DhcpConfigError, "unsupported parameter: " << entry
-                          << " (" << param.second->getPosition() << ")");
+            ConstElementPtr value(param.second);
+            try {
+                if (entry == "prefix") {
+                    addr_str = value->stringValue();
+                } else if (entry == "excluded-prefix") {
+                    excluded_prefix_str = value->stringValue();
+                } else if (entry == "prefix-len") {
+                    prefix_len = getUint8(entry, value);
+                } else if (entry == "delegated-len") {
+                    delegated_len = getUint8(entry, value);
+                } else if (entry == "excluded-prefix-len") {
+                    excluded_prefix_len = getUint8(entry, value);
+                } else if (entry == "option-data") {
+                    OptionDataListParser opts_parser(AF_INET6);
+                    opts_parser.parse(options_, value);
+                } else if (entry == "user-context") {
+                    user_context_ = value;
+                } else {
+                    isc_throw(isc::dhcp::DhcpConfigError,
+                              "unsupported parameter: " << entry
+                              << " (" << value->getPosition() << ")");
+                }
+            } catch (const isc::data::TypeError&) {
+                isc_throw(isc::dhcp::DhcpConfigError,
+                          "invalid value type specified for parameter '"
+                          << entry << "' ("
+                          << value->getPosition() << ")");
             }
             }
-
-            parser->build(param.second);
-            parser->commit();
         }
         }
 
 
-        // Try to obtain the pool parameters. It will throw an exception if any
+        // Check the pool parameters. It will throw an exception if any
         // of the required parameters are not present or invalid.
         // of the required parameters are not present or invalid.
+        require_("prefix", pd_pool_);
+        require_("prefix-len", pd_pool_);
+        require_("delegated-len", pd_pool_);
         try {
         try {
-            const std::string addr_str = string_values_->getParam("prefix");
-            const uint32_t prefix_len = uint32_values_->getParam("prefix-len");
-            const uint32_t delegated_len = uint32_values_->getParam("delegated-len");
-            const std::string excluded_prefix_str =
-                string_values_->getOptionalParam("excluded-prefix", "::");
-            const uint32_t excluded_prefix_len =
-                uint32_values_->getOptionalParam("excluded-prefix-len", 0);
-
             // Attempt to construct the local pool.
             // Attempt to construct the local pool.
-            pool_.reset(new Pool6(IOAddress(addr_str), prefix_len,
-                                  delegated_len, IOAddress(excluded_prefix_str),
+            pool_.reset(new Pool6(IOAddress(addr_str),
+                                  prefix_len,
+                                  delegated_len,
+                                  IOAddress(excluded_prefix_str),
                                   excluded_prefix_len));
                                   excluded_prefix_len));
             // Merge options specified for a pool into pool configuration.
             // Merge options specified for a pool into pool configuration.
             options_->copyTo(*pool_->getCfgOption());
             options_->copyTo(*pool_->getCfgOption());
@@ -231,30 +222,40 @@ public:
         if (user_context_) {
         if (user_context_) {
             pool_->setUserContext(user_context_);
             pool_->setUserContext(user_context_);
         }
         }
-    }
 
 
-    // @brief Commits the constructed local pool to the pool storage.
-    virtual void commit() {
         // Add the local pool to the external storage ptr.
         // Add the local pool to the external storage ptr.
-        pools_->push_back(pool_);
+        pools->push_back(pool_);
     }
     }
 
 
-protected:
-    /// Storage for subnet-specific integer values.
-    Uint32StoragePtr uint32_values_;
+private:
 
 
-    /// Storage for subnet-specific string values.
-    StringStoragePtr string_values_;
+    /// @brief Require a mandatory element
+    ///
+    /// @param name Entry name
+    /// @param config Pools configuration
+    /// @throw isc::dhcp::DhcpConfigError if not present
+    void require_(const std::string& name, ConstElementPtr config) const {
+        if (!config->contains(name)) {
+            isc_throw(isc::dhcp::DhcpConfigError,
+                      "Missing parameter '" << name << "' ("
+                      << config->getPosition() << ")");
+        }
+    }
 
 
-    /// Parsers are stored here.
-    ParserCollection parsers_;
+    /// @brief Get an uint8_t value
+    ///
+    /// @param name Entry name
+    /// @param value Integer element value
+    /// @return uint8_t value
+    /// @throw isc::data::TypeError when it is not an integer
+    /// isc::dhcp::DhcpConfigError when it does not fit in an uint8_t
+    uint8_t getUint8(const std::string& name, ConstElementPtr value) const {
+        return (extractInt<uint8_t, DhcpConfigError>(name, value));
+    }
 
 
     /// Pointer to the created pool object.
     /// Pointer to the created pool object.
     isc::dhcp::Pool6Ptr pool_;
     isc::dhcp::Pool6Ptr pool_;
 
 
-    /// Pointer to storage to which the local pool is written upon commit.
-    isc::dhcp::PoolStoragePtr pools_;
-
     /// A storage for pool specific option values.
     /// A storage for pool specific option values.
     CfgOptionPtr options_;
     CfgOptionPtr options_;
 
 
@@ -266,73 +267,27 @@ protected:
 /// This parser iterates over a list of prefix delegation pool entries and
 /// This parser iterates over a list of prefix delegation pool entries and
 /// creates pool instances for each one. If the parsing is successful, the
 /// creates pool instances for each one. If the parsing is successful, the
 /// collection of pools is committed to the provided storage.
 /// collection of pools is committed to the provided storage.
-class PdPoolListParser : public DhcpConfigParser {
+class PdPoolsListParser : public PoolsListParser {
 public:
 public:
-    /// @brief Constructor.
-    ///
-    /// @param dummy first argument is ignored, all Parser constructors
-    /// accept string as first argument.
-    /// @param storage is the pool storage in which to store the parsed
-    /// pools in this list
-    /// @throw isc::dhcp::DhcpConfigError if storage is null.
-    PdPoolListParser(const std::string&, PoolStoragePtr pools)
-        : local_pools_(new PoolStorage()), pools_(pools) {
-        if (!pools_) {
-            isc_throw(isc::dhcp::DhcpConfigError,
-                      "PdPoolListParser pools storage may not be NULL");
-        }
-    }
 
 
     /// @brief Parse configuration entries.
     /// @brief Parse configuration entries.
     ///
     ///
     /// This function parses configuration entries and creates instances
     /// This function parses configuration entries and creates instances
     /// of prefix delegation pools .
     /// of prefix delegation pools .
     ///
     ///
+    /// @param storage is the pool storage in which to store the parsed
     /// @param pd_pool_list pointer to an element that holds entries
     /// @param pd_pool_list pointer to an element that holds entries
     /// that define a prefix delegation pool.
     /// that define a prefix delegation pool.
     ///
     ///
     /// @throw DhcpConfigError if configuration parsing fails.
     /// @throw DhcpConfigError if configuration parsing fails.
-    void build(isc::data::ConstElementPtr pd_pool_list) {
-        // Make sure the local list is empty.
-        local_pools_.reset(new PoolStorage());
-
-        // Make sure we have a configuration elements to parse.
-        if (!pd_pool_list) {
-            isc_throw(DhcpConfigError,
-                      "PdPoolListParser: list of pool definitions is NULL");
-        }
-
+    void parse(PoolStoragePtr pools,
+               isc::data::ConstElementPtr pd_pool_list) {
         // Loop through the list of pd pools.
         // Loop through the list of pd pools.
         BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) {
         BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) {
-            boost::shared_ptr<PdPoolParser>
-                // Create the PdPool parser.
-                parser(new PdPoolParser("pd-pool", local_pools_));
-                // Build the pool instance
-                parser->build(pd_pool);
-                // Commit the pool to the local list of pools.
-                parser->commit();
+            PdPoolParser parser;
+            parser.parse(pools, pd_pool);
         }
         }
     }
     }
-
-    /// @brief  Commits the pools created to the external storage area.
-    ///
-    /// Note that this method adds the local list of pools to the storage area
-    /// rather than replacing its contents.  This permits other parsers to
-    /// contribute to the set of pools.
-    void commit() {
-        // local_pools_ holds the values produced by the build function.
-        // At this point parsing should have completed successfully so
-        // we can append new data to the supplied storage.
-        pools_->insert(pools_->end(), local_pools_->begin(),
-                       local_pools_->end());
-    }
-
-private:
-    /// @brief storage for local pools
-    PoolStoragePtr local_pools_;
-
-    /// @brief External storage where pools are stored upon list commit.
-    PoolStoragePtr pools_;
 };
 };
 
 
 /// @anchor Subnet6ConfigParser
 /// @anchor Subnet6ConfigParser
@@ -357,6 +312,18 @@ public:
     ///
     ///
     /// @param subnet A new subnet being configured.
     /// @param subnet A new subnet being configured.
     void build(ConstElementPtr subnet) {
     void build(ConstElementPtr subnet) {
+        /// Parse all pools first.
+        ConstElementPtr pools = subnet->get("pools");
+        if (pools) {
+            Pools6ListParser parser;
+            parser.parse(pools_, pools);
+        }
+        ConstElementPtr pd_pools = subnet->get("pd-pools");
+        if (pd_pools) {
+            PdPoolsListParser parser;
+            parser.parse(pools_, pd_pools);
+        }
+
         SubnetConfigParser::build(subnet);
         SubnetConfigParser::build(subnet);
 
 
         if (subnet_) {
         if (subnet_) {
@@ -421,11 +388,9 @@ protected:
                    (config_id.compare("interface-id") == 0) ||
                    (config_id.compare("interface-id") == 0) ||
                    (config_id.compare("reservation-mode") == 0)) {
                    (config_id.compare("reservation-mode") == 0)) {
             parser = new StringParser(config_id, string_values_);
             parser = new StringParser(config_id, string_values_);
-        } else if (config_id.compare("pools") == 0) {
-            parser = new Pools6ListParser(config_id, pools_);
+        // pools has been converted to SimpleParser.
         // relay has been converted to SimpleParser.
         // relay has been converted to SimpleParser.
-        } else if (config_id.compare("pd-pools") == 0) {
-            parser = new PdPoolListParser(config_id, pools_);
+        // pd-pools has been converted to SimpleParser.
         // option-data was here, but it is now converted to SimpleParser
         // option-data was here, but it is now converted to SimpleParser
         } else if (config_id.compare("rapid-commit") == 0) {
         } else if (config_id.compare("rapid-commit") == 0) {
             parser = new BooleanParser(config_id, boolean_values_);
             parser = new BooleanParser(config_id, boolean_values_);

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

@@ -1,4 +1,4 @@
-// Generated 201701251401
+// Generated 201701120056
 // 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++

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

@@ -1,4 +1,4 @@
-// Generated 201701251401
+// Generated 201701120056
 // 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 201701251401
+// Generated 201701120056
 // 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++

+ 204 - 7
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -118,7 +118,31 @@ const char* PARSER_CONFIGS[] = {
     "     } ]"
     "     } ]"
     "}",
     "}",
 
 
-    // Configuration 3: pd-pool without any user-context
+    // Configuration 3: one min-max pool with user context containing lw4over6 parameters
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [\"*\" ]"
+    "    },"
+    "    \"valid-lifetime\": 4000,"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000,"
+    "    \"renew-timer\": 1000,"
+    "    \"subnet6\": [ {"
+    "        \"pools\": [ "
+    "            { \"pool\":  \"2001:db8:: - 2001:db8::ffff:ffff:ffff:ffff\","
+    "                \"user-context\": {"
+    "                    \"lw4over6-sharing-ratio\": 64,"
+    "                    \"lw4over6-v4-pool\": \"192.0.2.0/24\","
+    "                    \"lw4over6-sysports-exclude\": true,"
+    "                    \"lw4over6-bind-prefix-len\": 56"
+    "                }"
+    "            }"
+    "        ],"
+    "        \"subnet\": \"2001:db8::/32\""
+    "     } ]"
+    "}",
+
+    // Configuration 4: pd-pool without any user-context
     "{"
     "{"
     "    \"interfaces-config\": {"
     "    \"interfaces-config\": {"
     "        \"interfaces\": [\"*\" ]"
     "        \"interfaces\": [\"*\" ]"
@@ -137,7 +161,7 @@ const char* PARSER_CONFIGS[] = {
     "     } ]"
     "     } ]"
     "}",
     "}",
 
 
-    // Configuration 4: pd-pool with empty user-context
+    // Configuration 5: pd-pool with empty user-context
     "{"
     "{"
     "    \"interfaces-config\": {"
     "    \"interfaces-config\": {"
     "        \"interfaces\": [\"*\" ]"
     "        \"interfaces\": [\"*\" ]"
@@ -158,7 +182,7 @@ const char* PARSER_CONFIGS[] = {
     "     } ]"
     "     } ]"
     "}",
     "}",
 
 
-    // Configuration 5: pd-pool with user-context with lw4over6 parameters
+    // Configuration 6: pd-pool with user-context with lw4over6 parameters
     "{"
     "{"
     "    \"interfaces-config\": {"
     "    \"interfaces-config\": {"
     "        \"interfaces\": [\"*\" ]"
     "        \"interfaces\": [\"*\" ]"
@@ -707,8 +731,9 @@ public:
     void getPool(const std::string& config, size_t subnet_index,
     void getPool(const std::string& config, size_t subnet_index,
                  size_t pool_index, Lease::Type type, PoolPtr& pool) {
                  size_t pool_index, Lease::Type type, PoolPtr& pool) {
         ConstElementPtr status;
         ConstElementPtr status;
-        ElementPtr json = Element::fromJSON(config);
+        ConstElementPtr json;
 
 
+        EXPECT_NO_THROW(json = parseDHCP6(config, true));
         EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
         EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
         ASSERT_TRUE(status);
         ASSERT_TRUE(status);
         checkResult(status, 0);
         checkResult(status, 0);
@@ -1487,6 +1512,139 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) {
     EXPECT_EQ(4000, subnet->getValid());
     EXPECT_EQ(4000, subnet->getValid());
 }
 }
 
 
+// Goal of this test is to verify if invalid pool definitions
+// return a location in the error message.
+TEST_F(Dhcp6ParserTest, badPools) {
+
+    // not a prefix
+    string config_bogus1 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo/80\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not a length
+    string config_bogus2 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/foo\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // invalid prefix length
+    string config_bogus3 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/200\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not a prefix nor a min-max
+    string config_bogus4 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // not an address
+    string config_bogus5 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"foo - bar\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // min > max
+    string config_bogus6 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::ffff - 2001:db8:1::\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    // out of range prefix length (new check)
+    string config_bogus7 = "{ " + genIfaceConfig() + ","
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/1104\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ConstElementPtr json1;
+    ASSERT_NO_THROW(json1 = parseDHCP6(config_bogus1));
+    ConstElementPtr json2;
+    ASSERT_NO_THROW(json2 = parseDHCP6(config_bogus2));
+    ConstElementPtr json3;
+    ASSERT_NO_THROW(json3 = parseDHCP6(config_bogus3));
+    ConstElementPtr json4;
+    ASSERT_NO_THROW(json4 = parseDHCP6(config_bogus4));
+    ConstElementPtr json5;
+    ASSERT_NO_THROW(json5 = parseDHCP6(config_bogus5));
+    ConstElementPtr json6;
+    ASSERT_NO_THROW(json6 = parseDHCP6(config_bogus6));
+    ConstElementPtr json7;
+    ASSERT_NO_THROW(json7 = parseDHCP6(config_bogus7));
+
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json1));
+
+    // check if returned status is always a failure
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json2));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json3));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json4));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json5));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json6));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+
+    CfgMgr::instance().clear();
+
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json7));
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+}
+
 // Goal of this test is to verify the basic parsing of a prefix delegation
 // Goal of this test is to verify the basic parsing of a prefix delegation
 // pool. It uses a single, valid pd pool.
 // pool. It uses a single, valid pd pool.
 TEST_F(Dhcp6ParserTest, pdPoolBasics) {
 TEST_F(Dhcp6ParserTest, pdPoolBasics) {
@@ -4865,11 +5023,50 @@ TEST_F(Dhcp6ParserTest, poolUserContextlw4over6) {
     EXPECT_EQ(56L, int_value);
     EXPECT_EQ(56L, int_value);
 }
 }
 
 
+// Test verifies that it's possible to specify parameters in the user context
+// in the min-max address pool.
+TEST_F(Dhcp6ParserTest, poolMinMaxUserContext) {
+    PoolPtr pool;
+    getPool(string(PARSER_CONFIGS[3]), 0, 0, Lease::TYPE_NA, pool);
+    ASSERT_TRUE(pool);
+    ConstElementPtr ctx = pool->getContext();
+    ASSERT_TRUE(ctx);
+
+    // The context should be of type map and contain 4 parameters.
+    EXPECT_EQ(Element::map, ctx->getType());
+    EXPECT_EQ(4, ctx->size());
+    ConstElementPtr ratio   = ctx->get("lw4over6-sharing-ratio");
+    ConstElementPtr v4pool  = ctx->get("lw4over6-v4-pool");
+    ConstElementPtr exclude = ctx->get("lw4over6-sysports-exclude");
+    ConstElementPtr v6len   = ctx->get("lw4over6-bind-prefix-len");
+
+    ASSERT_TRUE(ratio);
+    ASSERT_EQ(Element::integer, ratio->getType());
+    int64_t int_value;
+    EXPECT_NO_THROW(ratio->getValue(int_value));
+    EXPECT_EQ(64L, int_value);
+
+    ASSERT_TRUE(v4pool);
+    ASSERT_EQ(Element::string, v4pool->getType());
+    EXPECT_EQ("192.0.2.0/24", v4pool->stringValue());
+
+    ASSERT_TRUE(exclude);
+    bool bool_value;
+    ASSERT_EQ(Element::boolean, exclude->getType());
+    EXPECT_NO_THROW(exclude->getValue(bool_value));
+    EXPECT_EQ(true, bool_value);
+
+    ASSERT_TRUE(v6len);
+    ASSERT_EQ(Element::integer, v6len->getType());
+    EXPECT_NO_THROW(v6len->getValue(int_value));
+    EXPECT_EQ(56L, int_value);
+}
+
 // Test verifies that regular configuration does not provide any user context
 // Test verifies that regular configuration does not provide any user context
 // in the address pool.
 // in the address pool.
 TEST_F(Dhcp6ParserTest, pdPoolUserContextMissing) {
 TEST_F(Dhcp6ParserTest, pdPoolUserContextMissing) {
     PoolPtr pool;
     PoolPtr pool;
-    getPool(string(PARSER_CONFIGS[3]), 0, 0, Lease::TYPE_PD, pool);
+    getPool(string(PARSER_CONFIGS[4]), 0, 0, Lease::TYPE_PD, pool);
     ASSERT_TRUE(pool);
     ASSERT_TRUE(pool);
     EXPECT_FALSE(pool->getContext());
     EXPECT_FALSE(pool->getContext());
 }
 }
@@ -4878,7 +5075,7 @@ TEST_F(Dhcp6ParserTest, pdPoolUserContextMissing) {
 // address pool.
 // address pool.
 TEST_F(Dhcp6ParserTest, pdPoolUserContextEmpty) {
 TEST_F(Dhcp6ParserTest, pdPoolUserContextEmpty) {
     PoolPtr pool;
     PoolPtr pool;
-    getPool(string(PARSER_CONFIGS[4]), 0, 0, Lease::TYPE_PD, pool);
+    getPool(string(PARSER_CONFIGS[5]), 0, 0, Lease::TYPE_PD, pool);
     ASSERT_TRUE(pool);
     ASSERT_TRUE(pool);
     ConstElementPtr ctx = pool->getContext();
     ConstElementPtr ctx = pool->getContext();
     ASSERT_TRUE(ctx);
     ASSERT_TRUE(ctx);
@@ -4892,7 +5089,7 @@ TEST_F(Dhcp6ParserTest, pdPoolUserContextEmpty) {
 // in the address pool.
 // in the address pool.
 TEST_F(Dhcp6ParserTest, pdPoolUserContextlw4over6) {
 TEST_F(Dhcp6ParserTest, pdPoolUserContextlw4over6) {
     PoolPtr pool;
     PoolPtr pool;
-    getPool(string(PARSER_CONFIGS[5]), 0, 0, Lease::TYPE_PD, pool);
+    getPool(string(PARSER_CONFIGS[6]), 0, 0, Lease::TYPE_PD, pool);
     ASSERT_TRUE(pool);
     ASSERT_TRUE(pool);
     ConstElementPtr ctx = pool->getContext();
     ConstElementPtr ctx = pool->getContext();
     ASSERT_TRUE(ctx);
     ASSERT_TRUE(ctx);

+ 54 - 2
src/lib/cc/simple_parser.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-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
@@ -11,7 +11,7 @@
 #include <vector>
 #include <vector>
 #include <string>
 #include <string>
 #include <stdint.h>
 #include <stdint.h>
-#include <vector>
+#include <limits>
 
 
 namespace isc {
 namespace isc {
 namespace data {
 namespace data {
@@ -147,6 +147,58 @@ class SimpleParser {
     /// @return a boolean value of the parameter
     /// @return a boolean value of the parameter
     static bool getBoolean(isc::data::ConstElementPtr scope,
     static bool getBoolean(isc::data::ConstElementPtr scope,
                            const std::string& name);
                            const std::string& name);
+
+    /// @brief Returns an integer value with range checking
+    ///
+    /// This template should be instantied in parsers when useful
+    ///
+    /// @tparam int_type the integer type e.g. uint32_t
+    /// @tparam out_of_range always @c isc::dhcp::DhcpConfigError
+    /// @param name name of the parameter for error report
+    /// @param value value of the parameter
+    /// @return a value of int_type
+    /// @throw isc::data::TypeError when the value is not an integer
+    /// @throw out_of_range when the value does not fit in int_type
+    template <typename int_type, class out_of_range> int_type
+    extractInt(const std::string& name, ConstElementPtr value) const {
+        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(out_of_range, "out of range value (" << val_int
+                  << ") specified for parameter '" << name
+                      << "' (" << value->getPosition() << ")");
+        }
+        return (static_cast<int_type>(val_int));
+    }
+
+    /// @brief Returns a converted value
+    ///
+    /// This template should be instantied in parsers when useful
+    ///
+    /// @tparam target_type the type of the result
+    /// @tparam convert the conversion function std::string -> target_type
+    /// @tparam exception_type always @c isc::dhcp::DhcpConfigError
+    /// @param name name of the parameter for error report
+    /// @param type_name name of target_type for error report
+    /// @param value value of the parameter
+    /// @return a converted value of target_type
+    /// @throw isc::data::TypeError when the value is not an integer
+    /// @throw exception_type when the value cannot be converted
+    template <typename target_type,
+              target_type convert(const std::string&),
+              class exception_type> target_type
+    extractConvert(const std::string& name,
+                   const std::string& type_name,
+                   ConstElementPtr value) const {
+        std::string str = value->stringValue();
+        try {
+            return (convert(str));
+        } catch (const std::exception&) {
+            isc_throw(exception_type, "invalid " << type_name << " (" << str
+                      << ") specified for parameter '" << name
+                      << "' (" << value->getPosition() << ")");
+        }
+    }
 };
 };
 
 
 };
 };

+ 82 - 1
src/lib/cc/tests/simple_parser_unittest.cc

@@ -1,9 +1,10 @@
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-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
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
+#include <stdint.h>
 #include <cc/simple_parser.h>
 #include <cc/simple_parser.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
@@ -54,6 +55,43 @@ public:
     }
     }
 };
 };
 
 
+class SimpleParserClassTest : public SimpleParser {
+public:
+    /// @brief Instantiation of extractInt for uint8_t
+    ///
+    /// @param name name of the parameter for error report
+    /// @param value value of the parameter
+    /// @return an uint8_t value
+    uint8_t extractUint8(const std::string& name, ConstElementPtr value) const {
+        return (extractInt<uint8_t, isc::OutOfRange>(name, value));
+    }
+
+    /// @brief Instantiation of extractConvert
+    ///
+    /// @param name name of the parameter for error report
+    /// @param value value of the parameter
+    /// @return a bool value
+    bool extractBool(const std::string& name, ConstElementPtr value) const {
+        return (extractConvert<bool, toBool, isc::BadValue>
+                    (name, "boolean", value));
+    }
+
+    /// @brief Convert to boolean
+    ///
+    /// @param str the string "false" or "true"
+    /// @return false for "false" and true for "true"
+    /// @thrown isc::OutOfRange if not "false" or "true'
+    static bool toBool(const std::string& str) {
+        if (str == "false") {
+            return (false);
+        } else if (str == "true") {
+            return (true);
+        } else {
+            isc_throw(TypeError, "not a boolean: " << str);
+        }
+    }
+};
+
 // This test checks if the parameters can be inherited from the global
 // This test checks if the parameters can be inherited from the global
 // scope to the subnet scope.
 // scope to the subnet scope.
 TEST_F(SimpleParserTest, deriveParams) {
 TEST_F(SimpleParserTest, deriveParams) {
@@ -130,3 +168,46 @@ TEST_F(SimpleParserTest, setListDefaults) {
     checkIntegerValue(third, "rebind-timer", 1800);
     checkIntegerValue(third, "rebind-timer", 1800);
     checkIntegerValue(third, "renew-timer", 900);
     checkIntegerValue(third, "renew-timer", 900);
 }
 }
+
+// This test exercises the extractInt template
+TEST_F(SimpleParserTest, extractInt) {
+
+    SimpleParserClassTest parser;
+
+    // extractInt checks if it is an integer
+    ConstElementPtr not_int(new StringElement("xyz"));
+    EXPECT_THROW(parser.extractUint8("foo", not_int), TypeError);
+
+    // extractInt checks bounds
+    ConstElementPtr negative(new IntElement(-1));
+    EXPECT_THROW(parser.extractUint8("foo", negative), isc::OutOfRange);
+    ConstElementPtr too_large(new IntElement(1024));
+    EXPECT_THROW(parser.extractUint8("foo", too_large),isc::OutOfRange);
+
+    // checks if extractInt can return the expected value
+    ConstElementPtr hundred(new IntElement(100));
+    uint8_t val = 0;
+    EXPECT_NO_THROW(val = parser.extractUint8("foo", hundred));
+    EXPECT_EQ(100, val);
+}
+
+// This test exercises the extractConvert template
+TEST_F(SimpleParserTest, extractConvert) {
+
+    SimpleParserClassTest parser;
+
+    // extractConvert checks if it is a string
+    ConstElementPtr not_bool(new IntElement(1));
+    EXPECT_THROW(parser.extractBool("foo", not_bool), TypeError);
+
+    // checks if extractConvert can return the expected value
+    ConstElementPtr a_bool(new StringElement("false"));
+    bool val = true;
+    EXPECT_NO_THROW(val = parser.extractBool("foo", a_bool));
+    EXPECT_FALSE(val);
+
+    // extractConvert checks convertion
+    ConstElementPtr bad_bool(new StringElement("foo"));
+    EXPECT_THROW(parser.extractBool("bar", bad_bool), isc::BadValue);
+}
+

+ 61 - 82
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -845,60 +845,12 @@ RelayInfoParser::parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg,
     *cfg = isc::dhcp::Subnet::RelayInfo(ip);
     *cfg = isc::dhcp::Subnet::RelayInfo(ip);
 }
 }
 
 
-//****************************** PoolsListParser ********************************
-PoolsListParser::PoolsListParser(const std::string&, PoolStoragePtr pools)
-    :pools_(pools), local_pools_(new PoolStorage()) {
-    if (!pools_) {
-        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error: "
-                  << "storage may not be NULL");
-    }
-}
-
-void
-PoolsListParser::build(ConstElementPtr pools) {
-    BOOST_FOREACH(ConstElementPtr pool, pools->listValue()) {
-
-        // Iterate over every structure on the pools list and invoke
-        // a separate parser for it.
-        ParserPtr parser = poolParserMaker(local_pools_);
-
-        parser->build(pool);
-
-        // Let's store the parser, but do not commit anything yet
-        parsers_.push_back(parser);
-    }
-}
-
-void PoolsListParser::commit() {
-
-    // Commit each parser first. It will store the pool structure
-    // in pools_.
-    BOOST_FOREACH(ParserPtr parser, parsers_) {
-        parser->commit();
-    }
-
-    if (pools_) {
-        // local_pools_ holds the values produced by the build function.
-        // At this point parsing should have completed successfuly so
-        // we can append new data to the supplied storage.
-        pools_->insert(pools_->end(), local_pools_->begin(), local_pools_->end());
-    }
-}
-
 //****************************** PoolParser ********************************
 //****************************** PoolParser ********************************
-PoolParser::PoolParser(const std::string&, PoolStoragePtr pools,
-                       const uint16_t address_family)
-        :pools_(pools), options_(new CfgOption()),
-         address_family_(address_family) {
-
-    if (!pools_) {
-        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error: "
-                  << "storage may not be NULL");
-    }
-}
 
 
 void
 void
-PoolParser::build(ConstElementPtr pool_structure) {
+PoolParser::parse(PoolStoragePtr pools,
+                  ConstElementPtr pool_structure,
+                  const uint16_t address_family) {
 
 
     ConstElementPtr text_pool = pool_structure->get("pool");
     ConstElementPtr text_pool = pool_structure->get("pool");
 
 
@@ -936,38 +888,54 @@ PoolParser::build(ConstElementPtr pool_structure) {
             // digits (because there are extra characters left over).
             // digits (because there are extra characters left over).
 
 
             // No checks for values over 128. Range correctness will
             // No checks for values over 128. Range correctness will
-            // be checked in Pool4 constructor.
-            len = boost::lexical_cast<int>(prefix_len);
+            // be checked in Pool4 constructor, here we only check
+            // the representation fits in an uint8_t as this can't
+            // be done by a direct lexical cast as explained...
+            int val_len = boost::lexical_cast<int>(prefix_len);
+            if ((val_len < std::numeric_limits<uint8_t>::min()) ||
+                (val_len > std::numeric_limits<uint8_t>::max())) {
+                // This exception will be handled 4 line later!
+                isc_throw(OutOfRange, "");
+            }
+            len = static_cast<uint8_t>(val_len);
         } catch (...)  {
         } catch (...)  {
             isc_throw(DhcpConfigError, "Failed to parse pool "
             isc_throw(DhcpConfigError, "Failed to parse pool "
-                      "definition: " << text_pool->stringValue()
-                      << " (" << text_pool->getPosition() << ")");
+                      "definition: " << txt << " ("
+                      << text_pool->getPosition() << ")");
         }
         }
 
 
-        pool = poolMaker(addr, len);
-        local_pools_.push_back(pool);
-
-        // If there's user-context specified, store it.
-        ConstElementPtr user_context = pool_structure->get("user-context");
-        if (user_context) {
-            if (user_context->getType() != Element::map) {
-                isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
-                          << user_context->getPosition() << ")");
-            }
-            pool->setUserContext(user_context);
+        try {
+            pool = poolMaker(addr, len);
+            pools->push_back(pool);
+        } catch (const std::exception& ex) {
+            isc_throw(DhcpConfigError, "Failed to create pool defined by: "
+                      << txt << " (" << text_pool->getPosition() << ")");
         }
         }
 
 
     } else {
     } else {
+        isc::asiolink::IOAddress min("::");
+        isc::asiolink::IOAddress max("::");
 
 
         // Is this min-max notation?
         // Is this min-max notation?
         pos = txt.find("-");
         pos = txt.find("-");
         if (pos != string::npos) {
         if (pos != string::npos) {
             // using min-max notation
             // using min-max notation
-            isc::asiolink::IOAddress min(txt.substr(0,pos));
-            isc::asiolink::IOAddress max(txt.substr(pos + 1));
+            try {
+                min = isc::asiolink::IOAddress(txt.substr(0, pos));
+                max = isc::asiolink::IOAddress(txt.substr(pos + 1));
+            } catch (...)  {
+                isc_throw(DhcpConfigError, "Failed to parse pool "
+                          "definition: " << txt << " ("
+                          << text_pool->getPosition() << ")");
+            }
 
 
-            pool = poolMaker(min, max);
-            local_pools_.push_back(pool);
+            try {
+                pool = poolMaker(min, max);
+                pools->push_back(pool);
+            } catch (const std::exception& ex) {
+                isc_throw(DhcpConfigError, "Failed to create pool defined by: "
+                          << txt << " (" << text_pool->getPosition() << ")");
+            }
         }
         }
     }
     }
 
 
@@ -979,18 +947,28 @@ PoolParser::build(ConstElementPtr pool_structure) {
                   << text_pool->getPosition() << ")");
                   << text_pool->getPosition() << ")");
     }
     }
 
 
+    // If there's user-context specified, store it.
+    ConstElementPtr user_context = pool_structure->get("user-context");
+    if (user_context) {
+        if (user_context->getType() != Element::map) {
+            isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
+                      << user_context->getPosition() << ")");
+        }
+        pool->setUserContext(user_context);
+    }
+
     // Parser pool specific options.
     // Parser pool specific options.
     ConstElementPtr option_data = pool_structure->get("option-data");
     ConstElementPtr option_data = pool_structure->get("option-data");
     if (option_data) {
     if (option_data) {
         try {
         try {
             // Currently we don't support specifying options for the DHCPv4 server.
             // Currently we don't support specifying options for the DHCPv4 server.
-            if (address_family_ == AF_INET) {
+            if (address_family == AF_INET) {
                 isc_throw(DhcpConfigError, "option-data is not supported for DHCPv4"
                 isc_throw(DhcpConfigError, "option-data is not supported for DHCPv4"
                           " address pools");
                           " address pools");
             }
             }
 
 
             CfgOptionPtr cfg = pool->getCfgOption();
             CfgOptionPtr cfg = pool->getCfgOption();
-            OptionDataListParser option_parser(address_family_);
+            OptionDataListParser option_parser(address_family);
             option_parser.parse(cfg, option_data);
             option_parser.parse(cfg, option_data);
         } catch (const std::exception& ex) {
         } catch (const std::exception& ex) {
             isc_throw(isc::dhcp::DhcpConfigError, ex.what()
             isc_throw(isc::dhcp::DhcpConfigError, ex.what()
@@ -999,16 +977,6 @@ PoolParser::build(ConstElementPtr pool_structure) {
     }
     }
 }
 }
 
 
-void
-PoolParser::commit() {
-    if (pools_) {
-        // local_pools_ holds the values produced by the build function.
-        // At this point parsing should have completed successfuly so
-        // we can append new data to the supplied storage.
-        pools_->insert(pools_->end(), local_pools_.begin(), local_pools_.end());
-    }
-}
-
 //****************************** SubnetConfigParser *************************
 //****************************** SubnetConfigParser *************************
 
 
 SubnetConfigParser::SubnetConfigParser(const std::string&,
 SubnetConfigParser::SubnetConfigParser(const std::string&,
@@ -1033,6 +1001,17 @@ SubnetConfigParser::SubnetConfigParser(const std::string&,
 void
 void
 SubnetConfigParser::build(ConstElementPtr subnet) {
 SubnetConfigParser::build(ConstElementPtr subnet) {
     BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
     BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
+        // Pools has been converted to SimpleParser.
+        if (param.first == "pools") {
+            continue;
+        }
+
+        // PdPools has been converted to SimpleParser.
+        if ((param.first == "pd-pools") &&
+            (global_context_->universe_ == Option::V6)) {
+            continue;
+        }
+
         // Host reservations must be parsed after subnet specific parameters.
         // Host reservations must be parsed after subnet specific parameters.
         // Note that the reservation parsing will be invoked by the build()
         // Note that the reservation parsing will be invoked by the build()
         // in the derived classes, i.e. Subnet4ConfigParser and
         // in the derived classes, i.e. Subnet4ConfigParser and

+ 20 - 74
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -711,32 +711,25 @@ typedef boost::shared_ptr<PoolStorage> PoolStoragePtr;
 /// and stored in chosen PoolStorage container.
 /// and stored in chosen PoolStorage container.
 ///
 ///
 /// It is useful for parsing Dhcp<4/6>/subnet<4/6>[X]/pools[X] structure.
 /// It is useful for parsing Dhcp<4/6>/subnet<4/6>[X]/pools[X] structure.
-class PoolParser : public DhcpConfigParser {
+class PoolParser : public isc::data::SimpleParser {
 public:
 public:
 
 
-    /// @brief constructor.
-    ///
-    /// @param dummy first argument is ignored, all Parser constructors
-    /// accept string as first argument.
-    /// @param pools is the storage in which to store the parsed pool
-    /// upon "commit".
-    /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6).
-    /// @throw isc::dhcp::DhcpConfigError if storage is null.
-    PoolParser(const std::string& dummy, PoolStoragePtr pools,
-               const uint16_t address_family);
+    /// @brief destructor.
+    virtual ~PoolParser() {
+    }
 
 
     /// @brief parses the actual structure
     /// @brief parses the actual structure
     ///
     ///
     /// This method parses the actual list of interfaces.
     /// This method parses the actual list of interfaces.
     /// No validation is done at this stage, everything is interpreted as
     /// No validation is done at this stage, everything is interpreted as
     /// interface name.
     /// interface name.
+    /// @param pools is the storage in which to store the parsed pool
     /// @param pool_structure a single entry on a list of pools
     /// @param pool_structure a single entry on a list of pools
+    /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6).
     /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
     /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
-    virtual void build(isc::data::ConstElementPtr pool_structure);
-
-    /// @brief Stores the parsed values in a storage provided
-    ///        by an upper level parser.
-    virtual void commit();
+    virtual void parse(PoolStoragePtr pools,
+                       isc::data::ConstElementPtr pool_structure,
+                       const uint16_t address_family);
 
 
 protected:
 protected:
     /// @brief Creates a Pool object given a IPv4 prefix and the prefix length.
     /// @brief Creates a Pool object given a IPv4 prefix and the prefix length.
@@ -746,7 +739,7 @@ protected:
     /// @param ptype is the type of pool to create.
     /// @param ptype is the type of pool to create.
     /// @return returns a PoolPtr to the new Pool object.
     /// @return returns a PoolPtr to the new Pool object.
     virtual PoolPtr poolMaker(isc::asiolink::IOAddress &addr, uint32_t len,
     virtual PoolPtr poolMaker(isc::asiolink::IOAddress &addr, uint32_t len,
-                           int32_t ptype=0) = 0;
+                              int32_t ptype = 0) = 0;
 
 
     /// @brief Creates a Pool object given starting and ending IP addresses.
     /// @brief Creates a Pool object given starting and ending IP addresses.
     ///
     ///
@@ -755,23 +748,8 @@ protected:
     /// @param ptype is the type of pool to create (not used by all derivations)
     /// @param ptype is the type of pool to create (not used by all derivations)
     /// @return returns a PoolPtr to the new Pool object.
     /// @return returns a PoolPtr to the new Pool object.
     virtual PoolPtr poolMaker(isc::asiolink::IOAddress &min,
     virtual PoolPtr poolMaker(isc::asiolink::IOAddress &min,
-                           isc::asiolink::IOAddress &max, int32_t ptype=0) = 0;
-
-    /// @brief pointer to the actual Pools storage
-    ///
-    /// That is typically a storage somewhere in Subnet parser
-    /// (an upper level parser).
-    PoolStoragePtr pools_;
-
-    /// A temporary storage for pools configuration. It is a
-    /// storage where pools are stored by build function.
-    PoolStorage local_pools_;
-
-    /// A storage for pool specific option values.
-    CfgOptionPtr options_;
-
-    /// @brief Address family: AF_INET (for DHCPv4) or AF_INET6 for DHCPv6.
-    uint16_t address_family_;
+                              isc::asiolink::IOAddress &max,
+                              int32_t ptype = 0) = 0;
 };
 };
 
 
 /// @brief Parser for a list of pools
 /// @brief Parser for a list of pools
@@ -779,54 +757,22 @@ protected:
 /// This parser parses a list pools. Each element on that list gets its own
 /// This parser parses a list pools. Each element on that list gets its own
 /// parser, created with poolParserMaker() method. That method must be specified
 /// parser, created with poolParserMaker() method. That method must be specified
 /// for each protocol family (v4 or v6) separately.
 /// for each protocol family (v4 or v6) separately.
-///
-/// This class is not intended to be used directly. Instead, derived classes
-/// should implement poolParserMaker() method.
-class PoolsListParser :  public DhcpConfigParser {
+class PoolsListParser : public isc::data::SimpleParser {
 public:
 public:
 
 
-    /// @brief constructor.
-    ///
-    /// @param dummy first argument is ignored, all Parser constructors
-    /// accept a string as the first argument.
-    /// @param pools is the storage in which to store the parsed pool
-    /// upon "commit".
-    /// @throw isc::dhcp::DhcpConfigError if storage is null.
-    PoolsListParser(const std::string& dummy, PoolStoragePtr pools);
+    /// @brief destructor.
+    virtual ~PoolsListParser() {
+    }
 
 
     /// @brief parses the actual structure
     /// @brief parses the actual structure
     ///
     ///
-    /// This method parses the actual list of pools. It creates a parser
-    /// for each structure using poolParserMaker().
+    /// This method parses the actual list of pools.
     ///
     ///
+    /// @param pools is the storage in which to store the parsed pools.
     /// @param pools_list a list of pool structures
     /// @param pools_list a list of pool structures
     /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
     /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
-    virtual void build(isc::data::ConstElementPtr pools_list);
-
-    /// @brief Stores the parsed values in storage provided
-    ///        by an upper level parser.
-    virtual void commit();
-
-protected:
-
-    /// @brief Creates a PoolParser object
-    ///
-    /// Instantiates appropriate (v4 or v6) PoolParser object.
-    /// @param storage parameter that is passed to ParserMaker() constructor.
-    virtual ParserPtr poolParserMaker(PoolStoragePtr storage) = 0;
-
-    /// @brief pointer to the actual Pools storage
-    ///
-    /// That is typically a storage somewhere in Subnet parser
-    /// (an upper level parser).
-    PoolStoragePtr pools_;
-
-    /// A temporary storage for pools configuration. It is the
-    /// storage where pools are stored by the build function.
-    PoolStoragePtr local_pools_;
-
-    /// Collection of parsers;
-    ParserCollection parsers_;
+    virtual void parse(PoolStoragePtr pools,
+                       isc::data::ConstElementPtr pools_list) = 0;
 };
 };
 
 
 /// @brief parser for additional relay information
 /// @brief parser for additional relay information