Browse Source

[master] Merged trac5124a (required params in grammar)

Francis Dupont 7 years ago
parent
commit
75887c7372

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


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

@@ -119,6 +119,10 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp4Parser::make_SUB_POOL4(driver.loc_);
             return isc::dhcp::Dhcp4Parser::make_SUB_POOL4(driver.loc_);
         case Parser4Context::PARSER_HOST_RESERVATION:
         case Parser4Context::PARSER_HOST_RESERVATION:
             return isc::dhcp::Dhcp4Parser::make_SUB_RESERVATION(driver.loc_);
             return isc::dhcp::Dhcp4Parser::make_SUB_RESERVATION(driver.loc_);
+        case Parser4Context::PARSER_OPTION_DEFS:
+            return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DEFS(driver.loc_);
+        case Parser4Context::PARSER_OPTION_DEF:
+            return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DEF(driver.loc_);
         case Parser4Context::PARSER_OPTION_DATA:
         case Parser4Context::PARSER_OPTION_DATA:
             return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DATA(driver.loc_);
             return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DATA(driver.loc_);
         case Parser4Context::PARSER_HOOKS_LIBRARY:
         case Parser4Context::PARSER_HOOKS_LIBRARY:

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


+ 72 - 60
src/bin/dhcp4/dhcp4_parser.h

@@ -481,14 +481,15 @@ namespace isc { namespace dhcp {
         TOKEN_SUB_SUBNET4 = 389,
         TOKEN_SUB_SUBNET4 = 389,
         TOKEN_SUB_POOL4 = 390,
         TOKEN_SUB_POOL4 = 390,
         TOKEN_SUB_RESERVATION = 391,
         TOKEN_SUB_RESERVATION = 391,
-        TOKEN_SUB_OPTION_DEF = 392,
-        TOKEN_SUB_OPTION_DATA = 393,
-        TOKEN_SUB_HOOKS_LIBRARY = 394,
-        TOKEN_SUB_DHCP_DDNS = 395,
-        TOKEN_STRING = 396,
-        TOKEN_INTEGER = 397,
-        TOKEN_FLOAT = 398,
-        TOKEN_BOOLEAN = 399
+        TOKEN_SUB_OPTION_DEFS = 392,
+        TOKEN_SUB_OPTION_DEF = 393,
+        TOKEN_SUB_OPTION_DATA = 394,
+        TOKEN_SUB_HOOKS_LIBRARY = 395,
+        TOKEN_SUB_DHCP_DDNS = 396,
+        TOKEN_STRING = 397,
+        TOKEN_INTEGER = 398,
+        TOKEN_FLOAT = 399,
+        TOKEN_BOOLEAN = 400
       };
       };
     };
     };
 
 
@@ -1145,6 +1146,10 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
+    make_SUB_OPTION_DEFS (const location_type& l);
+
+    static inline
+    symbol_type
     make_SUB_OPTION_DEF (const location_type& l);
     make_SUB_OPTION_DEF (const location_type& l);
 
 
     static inline
     static inline
@@ -1380,12 +1385,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 756,     ///< Last index in yytable_.
-      yynnts_ = 318,  ///< Number of nonterminal symbols.
-      yyfinal_ = 24, ///< Termination state number.
+      yylast_ = 755,     ///< Last index in yytable_.
+      yynnts_ = 321,  ///< Number of nonterminal symbols.
+      yyfinal_ = 26, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 145  ///< Number of tokens.
+      yyntokens_ = 146  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1441,9 +1446,10 @@ namespace isc { namespace dhcp {
      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,
      125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
-     135,   136,   137,   138,   139,   140,   141,   142,   143,   144
+     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+     145
     };
     };
-    const unsigned int user_token_number_max_ = 399;
+    const unsigned int user_token_number_max_ = 400;
     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_)
@@ -1476,29 +1482,29 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 200: // socket_type
-      case 210: // db_type
-      case 287: // hr_mode
-      case 420: // ncr_protocol_value
-      case 428: // replace_client_name_value
+      case 160: // value
+      case 164: // map_value
+      case 202: // socket_type
+      case 212: // db_type
+      case 289: // hr_mode
+      case 424: // ncr_protocol_value
+      case 432: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 144: // "boolean"
+      case 145: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 143: // "floating point"
+      case 144: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 142: // "integer"
+      case 143: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 141: // "constant string"
+      case 142: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1519,29 +1525,29 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 200: // socket_type
-      case 210: // db_type
-      case 287: // hr_mode
-      case 420: // ncr_protocol_value
-      case 428: // replace_client_name_value
+      case 160: // value
+      case 164: // map_value
+      case 202: // socket_type
+      case 212: // db_type
+      case 289: // hr_mode
+      case 424: // ncr_protocol_value
+      case 432: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 144: // "boolean"
+      case 145: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 143: // "floating point"
+      case 144: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 142: // "integer"
+      case 143: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 141: // "constant string"
+      case 142: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1621,29 +1627,29 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 200: // socket_type
-      case 210: // db_type
-      case 287: // hr_mode
-      case 420: // ncr_protocol_value
-      case 428: // replace_client_name_value
+      case 160: // value
+      case 164: // map_value
+      case 202: // socket_type
+      case 212: // db_type
+      case 289: // hr_mode
+      case 424: // ncr_protocol_value
+      case 432: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 144: // "boolean"
+      case 145: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 143: // "floating point"
+      case 144: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 142: // "integer"
+      case 143: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 141: // "constant string"
+      case 142: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1670,29 +1676,29 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 200: // socket_type
-      case 210: // db_type
-      case 287: // hr_mode
-      case 420: // ncr_protocol_value
-      case 428: // replace_client_name_value
+      case 160: // value
+      case 164: // map_value
+      case 202: // socket_type
+      case 212: // db_type
+      case 289: // hr_mode
+      case 424: // ncr_protocol_value
+      case 432: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 144: // "boolean"
+      case 145: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 143: // "floating point"
+      case 144: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 142: // "integer"
+      case 143: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 141: // "constant string"
+      case 142: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1765,7 +1771,7 @@ namespace isc { namespace dhcp {
      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,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,   399
+     395,   396,   397,   398,   399,   400
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -2581,6 +2587,12 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
+  Dhcp4Parser::make_SUB_OPTION_DEFS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SUB_OPTION_DEFS, l);
+  }
+
+  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_SUB_OPTION_DEF (const location_type& l)
   Dhcp4Parser::make_SUB_OPTION_DEF (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_SUB_OPTION_DEF, l);
     return symbol_type (token::TOKEN_SUB_OPTION_DEF, l);
@@ -2631,7 +2643,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 2635 "dhcp4_parser.h" // lalr1.cc:377
+#line 2647 "dhcp4_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 56 - 4
src/bin/dhcp4/dhcp4_parser.yy

@@ -195,6 +195,7 @@ using namespace std;
   SUB_SUBNET4
   SUB_SUBNET4
   SUB_POOL4
   SUB_POOL4
   SUB_RESERVATION
   SUB_RESERVATION
+  SUB_OPTION_DEFS
   SUB_OPTION_DEF
   SUB_OPTION_DEF
   SUB_OPTION_DATA
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_HOOKS_LIBRARY
@@ -230,6 +231,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_SUBNET4 { ctx.ctx_ = ctx.SUBNET4; } sub_subnet4
      | SUB_SUBNET4 { ctx.ctx_ = ctx.SUBNET4; } sub_subnet4
      | SUB_POOL4 { ctx.ctx_ = ctx.POOLS; } sub_pool4
      | SUB_POOL4 { ctx.ctx_ = ctx.POOLS; } sub_pool4
      | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
      | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
+     | SUB_OPTION_DEFS { ctx.ctx_ = ctx.DHCP4; } sub_option_def_list
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
@@ -351,6 +353,9 @@ syntax_map: LCURLY_BRACKET {
     // map parsing completed. If we ever want to do any wrap up
     // map parsing completed. If we ever want to do any wrap up
     // (maybe some sanity checking), this would be the best place
     // (maybe some sanity checking), this would be the best place
     // for it.
     // for it.
+
+    // Dhcp4 is required
+    ctx.require("Dhcp4", ctx.loc2pos(@1), ctx.loc2pos(@4));
 };
 };
 
 
 // This represents top-level entries: Control-agent, Dhcp6, Dhcp4,
 // This represents top-level entries: Control-agent, Dhcp6, Dhcp4,
@@ -376,9 +381,7 @@ dhcp4_object: DHCP4 {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP4);
     ctx.enter(ctx.DHCP4);
 } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
-    // map parsing completed. If we ever want to do any wrap up
-    // (maybe some sanity checking), this would be the best place
-    // for it.
+    // No global parameter is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -390,6 +393,7 @@ sub_dhcp4: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } global_params RCURLY_BRACKET {
 } global_params RCURLY_BRACKET {
+    // No global parameter is required
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -459,6 +463,7 @@ interfaces_config: INTERFACES_CONFIG {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.INTERFACES_CONFIG);
     ctx.enter(ctx.INTERFACES_CONFIG);
 } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
+    // No interfaces config param is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -477,6 +482,7 @@ sub_interfaces4: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } interfaces_config_params RCURLY_BRACKET {
 } interfaces_config_params RCURLY_BRACKET {
+    // No interfaces config param is required
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -513,6 +519,8 @@ lease_database: LEASE_DATABASE {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.LEASE_DATABASE);
     ctx.enter(ctx.LEASE_DATABASE);
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+    // The type parameter is required
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -523,6 +531,8 @@ hosts_database: HOSTS_DATABASE {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.HOSTS_DATABASE);
     ctx.enter(ctx.HOSTS_DATABASE);
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+    // The type parameter is required
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -702,6 +712,8 @@ hooks_library: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } hooks_params RCURLY_BRACKET {
 } hooks_params RCURLY_BRACKET {
+    // The library hooks parameter is required
+    ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -710,6 +722,8 @@ sub_hooks_library: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } hooks_params RCURLY_BRACKET {
 } hooks_params RCURLY_BRACKET {
+    // The library hooks parameter is required
+    ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -744,6 +758,7 @@ expired_leases_processing: EXPIRED_LEASES_PROCESSING {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
     ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
 } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
+    // No expired lease parameter is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -838,6 +853,9 @@ subnet4: LCURLY_BRACKET {
     //         ctx.stack_.back()->set("renew-timer", renew);
     //         ctx.stack_.back()->set("renew-timer", renew);
     //     }
     //     }
     // }
     // }
+
+    // The subnet subnet4 parameter is required
+    ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -846,6 +864,8 @@ sub_subnet4: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } subnet4_params RCURLY_BRACKET {
 } subnet4_params RCURLY_BRACKET {
+    // The subnet subnet4 parameter is required
+    ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -969,6 +989,16 @@ option_def_list: OPTION_DEF {
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+// This defines the top level scope when the parser is told to parse
+// option definitions. It works as a subset limited to option
+// definitions
+sub_option_def_list: LCURLY_BRACKET {
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} option_def_list RCURLY_BRACKET {
+    // parsing completed
+};
+
 // This defines the content of option-def. It may be empty,
 // This defines the content of option-def. It may be empty,
 // have one entry or multiple entries separated by comma.
 // have one entry or multiple entries separated by comma.
 option_def_list_content: %empty
 option_def_list_content: %empty
@@ -986,6 +1016,10 @@ option_def_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_def_params RCURLY_BRACKET {
 } option_def_params RCURLY_BRACKET {
+    // The name, code and type option def parameters are required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -997,6 +1031,10 @@ sub_option_def: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_def_params RCURLY_BRACKET {
 } option_def_params RCURLY_BRACKET {
+    // The name, code and type option def parameters are required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1101,6 +1139,7 @@ option_data_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_data_params RCURLY_BRACKET {
 } option_data_params RCURLY_BRACKET {
+    /// @todo: the code or name parameters are required.
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1112,6 +1151,7 @@ sub_option_data: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_data_params RCURLY_BRACKET {
 } option_data_params RCURLY_BRACKET {
+    /// @todo: the code or name parameters are required.
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1191,6 +1231,8 @@ pool_list_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pool_params RCURLY_BRACKET {
 } pool_params RCURLY_BRACKET {
+    // The pool parameter is required.
+    ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1199,6 +1241,8 @@ sub_pool4: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pool_params RCURLY_BRACKET {
 } pool_params RCURLY_BRACKET {
+    // The pool parameter is required.
+    ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1253,6 +1297,7 @@ reservation: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } reservation_params RCURLY_BRACKET {
 } reservation_params RCURLY_BRACKET {
+    /// @todo: an identifier parameter is required.
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1261,6 +1306,7 @@ sub_reservation: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } reservation_params RCURLY_BRACKET {
 } reservation_params RCURLY_BRACKET {
+    /// @todo: an identifier parameter is required.
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1272,7 +1318,7 @@ not_empty_reservation_params: reservation_param
     | not_empty_reservation_params COMMA reservation_param
     | not_empty_reservation_params COMMA reservation_param
     ;
     ;
 
 
-// @todo probably need to add mac-address as well here
+/// @todo probably need to add mac-address as well here
 reservation_param: duid
 reservation_param: duid
                  | reservation_client_classes
                  | reservation_client_classes
                  | client_id_value
                  | client_id_value
@@ -1421,6 +1467,8 @@ client_class: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } client_class_params RCURLY_BRACKET {
 } client_class_params RCURLY_BRACKET {
+    // The name client class parameter is required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1504,6 +1552,8 @@ dhcp_ddns: DHCP_DDNS {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP_DDNS);
     ctx.enter(ctx.DHCP_DDNS);
 } COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
+    // The enable updates DHCP DDNS parameter is required.
+    ctx.require("enable-updates", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -1513,6 +1563,8 @@ sub_dhcp_ddns: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } dhcp_ddns_params RCURLY_BRACKET {
 } dhcp_ddns_params RCURLY_BRACKET {
+    // The enable updates DHCP DDNS parameter is required.
+    ctx.require("enable-updates", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 

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

@@ -1,4 +1,4 @@
-// Generated 201708070754
+// Generated 201709021237
 // 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++

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

@@ -74,13 +74,13 @@ Parser4Context::error(const isc::dhcp::location& loc, const std::string& what)
 }
 }
 
 
 void
 void
-Parser4Context::error (const std::string& what)
+Parser4Context::error(const std::string& what)
 {
 {
     isc_throw(Dhcp4ParseError, what);
     isc_throw(Dhcp4ParseError, what);
 }
 }
 
 
 void
 void
-Parser4Context::fatal (const std::string& what)
+Parser4Context::fatal(const std::string& what)
 {
 {
     isc_throw(Dhcp4ParseError, what);
     isc_throw(Dhcp4ParseError, what);
 }
 }
@@ -95,6 +95,21 @@ Parser4Context::loc2pos(isc::dhcp::location& loc)
 }
 }
 
 
 void
 void
+Parser4Context::require(const std::string& name,
+                        isc::data::Element::Position open_loc,
+                        isc::data::Element::Position close_loc)
+{
+    ConstElementPtr value = stack_.back()->get(name);
+    if (!value) {
+        isc_throw(Dhcp4ParseError,
+                  "missing parameter '" << name << "' ("
+                  << stack_.back()->getPosition() << ") ["
+                  << contextName() << " map between "
+                  << open_loc << " and " << close_loc << "]");
+    }
+}
+
+void
 Parser4Context::enter(const ParserContext& ctx)
 Parser4Context::enter(const ParserContext& ctx)
 {
 {
     cstack_.push_back(ctx_);
     cstack_.push_back(ctx_);

+ 16 - 0
src/bin/dhcp4/parser_context.h

@@ -73,6 +73,9 @@ public:
         /// This will parse the input as host-reservation.
         /// This will parse the input as host-reservation.
         PARSER_HOST_RESERVATION,
         PARSER_HOST_RESERVATION,
 
 
+        /// This will parse the input option definitions (for tests).
+        PARSER_OPTION_DEFS,
+
         /// This will parse the input as option definition.
         /// This will parse the input as option definition.
         PARSER_OPTION_DEF,
         PARSER_OPTION_DEF,
 
 
@@ -176,6 +179,19 @@ public:
     /// @return Position in format accepted by Element
     /// @return Position in format accepted by Element
     isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
     isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
 
 
+    /// @brief Check if a required parameter is present
+    ///
+    /// Check if a required parameter is present in the map at the top
+    /// of the stack and raise an error when it is not.
+    ///
+    /// @param name name of the parameter to check
+    /// @param open_loc location of the opening curly bracket
+    /// @param close_loc ocation of the closing curly bracket
+    /// @throw Dhcp4ParseError
+    void require(const std::string& name,
+                 isc::data::Element::Position open_loc,
+                 isc::data::Element::Position close_loc);
+
     /// @brief Defines syntactic contexts for lexical tie-ins
     /// @brief Defines syntactic contexts for lexical tie-ins
     typedef enum {
     typedef enum {
         ///< This one is used in pure JSON mode.
         ///< This one is used in pure JSON mode.

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

@@ -1,4 +1,4 @@
-// Generated 201708070754
+// Generated 201709021237
 // 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 201708070754
+// Generated 201709021237
 // 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++

+ 18 - 20
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -1618,7 +1618,7 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config, true));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config, true));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -1659,10 +1659,8 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
 
 
     // Let's apply empty configuration. This removes the option definitions
     // Let's apply empty configuration. This removes the option definitions
     // configuration and should result in removal of the option 100 from the
     // configuration and should result in removal of the option 100 from the
-    // libdhcp++.
-    config = "{ }";
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config, true));
-
+    // libdhcp++. Note DHCP4 or OPTION_DEFS parsers do not accept empty maps.
+    json.reset(new MapElement());
     ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     checkResult(status, 0);
     checkResult(status, 0);
 
 
@@ -1685,7 +1683,7 @@ TEST_F(Dhcp4ParserTest, optionDefRecord) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -1740,7 +1738,7 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the option definitions do not exist yet.
     // Make sure that the option definitions do not exist yet.
@@ -1810,7 +1808,7 @@ TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Make sure that the option definition does not exist yet.
     // Make sure that the option definition does not exist yet.
     ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
     ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
@@ -1849,7 +1847,7 @@ TEST_F(Dhcp4ParserTest, optionDefArray) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -1892,7 +1890,7 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulate) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -1933,7 +1931,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidName) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -1958,7 +1956,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidType) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -1984,7 +1982,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidRecordType) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2010,7 +2008,7 @@ TEST_F(Dhcp4ParserTest, optionIntegerTypes) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2035,7 +2033,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidEncapsulatedSpace) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2064,7 +2062,7 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulatedSpaceAndArray) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2090,7 +2088,7 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulateOwnSpace) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2119,7 +2117,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
     OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
@@ -2154,7 +2152,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
         "      \"space\": \"dhcp4\""
         "      \"space\": \"dhcp4\""
         "  } ]"
         "  } ]"
         "}";
         "}";
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
@@ -2176,7 +2174,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
         "      \"space\": \"dhcp4\""
         "      \"space\": \"dhcp4\""
         "  } ]"
         "  } ]"
         "}";
         "}";
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.

+ 2 - 2
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -536,11 +536,11 @@ parseDHCP4(const std::string& in, bool verbose = false)
 /// @param verbose display the exception message when it fails
 /// @param verbose display the exception message when it fails
 /// @return ElementPtr structure representing parsed JSON
 /// @return ElementPtr structure representing parsed JSON
 inline isc::data::ElementPtr
 inline isc::data::ElementPtr
-parseOPTION_DEF(const std::string& in, bool verbose = false)
+parseOPTION_DEFS(const std::string& in, bool verbose = false)
 {
 {
     try {
     try {
         isc::dhcp::Parser4Context ctx;
         isc::dhcp::Parser4Context ctx;
-        return (ctx.parseString(in, isc::dhcp::Parser4Context::PARSER_OPTION_DEF));
+        return (ctx.parseString(in, isc::dhcp::Parser4Context::PARSER_OPTION_DEFS));
     }
     }
     catch (const std::exception& ex) {
     catch (const std::exception& ex) {
         if (verbose) {
         if (verbose) {

+ 7 - 0
src/bin/dhcp4/tests/parser_unittest.cc

@@ -501,6 +501,13 @@ TEST(ParserTest, errors) {
               Parser4Context::PARSER_DHCP4,
               Parser4Context::PARSER_DHCP4,
               "<string>:2.2-17: got unexpected keyword "
               "<string>:2.2-17: got unexpected keyword "
               "\"valid_lifetime\" in Dhcp4 map.");
               "\"valid_lifetime\" in Dhcp4 map.");
+
+    // missing parameter
+    testError("{ \"name\": \"foo\",\n"
+              "  \"code\": 123 }\n",
+              Parser4Context::PARSER_OPTION_DEF,
+              "missing parameter 'type' (<string>:1:1) "
+              "[option-def map between <string>:1:1 and <string>:2:15]");
 }
 }
 
 
 // Check unicode escapes
 // Check unicode escapes

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


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

@@ -121,6 +121,10 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp6Parser::make_SUB_PD_POOL(driver.loc_);
             return isc::dhcp::Dhcp6Parser::make_SUB_PD_POOL(driver.loc_);
         case Parser6Context::PARSER_HOST_RESERVATION:
         case Parser6Context::PARSER_HOST_RESERVATION:
             return isc::dhcp::Dhcp6Parser::make_SUB_RESERVATION(driver.loc_);
             return isc::dhcp::Dhcp6Parser::make_SUB_RESERVATION(driver.loc_);
+        case Parser6Context::PARSER_OPTION_DEFS:
+            return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DEFS(driver.loc_);
+        case Parser6Context::PARSER_OPTION_DEF:
+            return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DEF(driver.loc_);
         case Parser6Context::PARSER_OPTION_DATA:
         case Parser6Context::PARSER_OPTION_DATA:
             return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
             return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
         case Parser6Context::PARSER_HOOKS_LIBRARY:
         case Parser6Context::PARSER_HOOKS_LIBRARY:

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


+ 71 - 60
src/bin/dhcp6/dhcp6_parser.h

@@ -489,14 +489,15 @@ namespace isc { namespace dhcp {
         TOKEN_SUB_POOL6 = 397,
         TOKEN_SUB_POOL6 = 397,
         TOKEN_SUB_PD_POOL = 398,
         TOKEN_SUB_PD_POOL = 398,
         TOKEN_SUB_RESERVATION = 399,
         TOKEN_SUB_RESERVATION = 399,
-        TOKEN_SUB_OPTION_DEF = 400,
-        TOKEN_SUB_OPTION_DATA = 401,
-        TOKEN_SUB_HOOKS_LIBRARY = 402,
-        TOKEN_SUB_DHCP_DDNS = 403,
-        TOKEN_STRING = 404,
-        TOKEN_INTEGER = 405,
-        TOKEN_FLOAT = 406,
-        TOKEN_BOOLEAN = 407
+        TOKEN_SUB_OPTION_DEFS = 400,
+        TOKEN_SUB_OPTION_DEF = 401,
+        TOKEN_SUB_OPTION_DATA = 402,
+        TOKEN_SUB_HOOKS_LIBRARY = 403,
+        TOKEN_SUB_DHCP_DDNS = 404,
+        TOKEN_STRING = 405,
+        TOKEN_INTEGER = 406,
+        TOKEN_FLOAT = 407,
+        TOKEN_BOOLEAN = 408
       };
       };
     };
     };
 
 
@@ -1185,6 +1186,10 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
+    make_SUB_OPTION_DEFS (const location_type& l);
+
+    static inline
+    symbol_type
     make_SUB_OPTION_DEF (const location_type& l);
     make_SUB_OPTION_DEF (const location_type& l);
 
 
     static inline
     static inline
@@ -1420,12 +1425,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 804,     ///< Last index in yytable_.
-      yynnts_ = 335,  ///< Number of nonterminal symbols.
-      yyfinal_ = 26, ///< Termination state number.
+      yylast_ = 803,     ///< Last index in yytable_.
+      yynnts_ = 338,  ///< Number of nonterminal symbols.
+      yyfinal_ = 28, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 153  ///< Number of tokens.
+      yyntokens_ = 154  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1482,9 +1487,9 @@ namespace isc { namespace dhcp {
      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,
      125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
      135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
      135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
-     145,   146,   147,   148,   149,   150,   151,   152
+     145,   146,   147,   148,   149,   150,   151,   152,   153
     };
     };
-    const unsigned int user_token_number_max_ = 407;
+    const unsigned int user_token_number_max_ = 408;
     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_)
@@ -1517,29 +1522,29 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 167: // value
-      case 171: // map_value
-      case 215: // db_type
-      case 291: // hr_mode
-      case 412: // duid_type
-      case 445: // ncr_protocol_value
-      case 453: // replace_client_name_value
+      case 169: // value
+      case 173: // map_value
+      case 217: // db_type
+      case 293: // hr_mode
+      case 416: // duid_type
+      case 449: // ncr_protocol_value
+      case 457: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 152: // "boolean"
+      case 153: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 151: // "floating point"
+      case 152: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 150: // "integer"
+      case 151: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 149: // "constant string"
+      case 150: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1560,29 +1565,29 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 167: // value
-      case 171: // map_value
-      case 215: // db_type
-      case 291: // hr_mode
-      case 412: // duid_type
-      case 445: // ncr_protocol_value
-      case 453: // replace_client_name_value
+      case 169: // value
+      case 173: // map_value
+      case 217: // db_type
+      case 293: // hr_mode
+      case 416: // duid_type
+      case 449: // ncr_protocol_value
+      case 457: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 152: // "boolean"
+      case 153: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 151: // "floating point"
+      case 152: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 150: // "integer"
+      case 151: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 149: // "constant string"
+      case 150: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1662,29 +1667,29 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 167: // value
-      case 171: // map_value
-      case 215: // db_type
-      case 291: // hr_mode
-      case 412: // duid_type
-      case 445: // ncr_protocol_value
-      case 453: // replace_client_name_value
+      case 169: // value
+      case 173: // map_value
+      case 217: // db_type
+      case 293: // hr_mode
+      case 416: // duid_type
+      case 449: // ncr_protocol_value
+      case 457: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 152: // "boolean"
+      case 153: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 151: // "floating point"
+      case 152: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 150: // "integer"
+      case 151: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 149: // "constant string"
+      case 150: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1711,29 +1716,29 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 167: // value
-      case 171: // map_value
-      case 215: // db_type
-      case 291: // hr_mode
-      case 412: // duid_type
-      case 445: // ncr_protocol_value
-      case 453: // replace_client_name_value
+      case 169: // value
+      case 173: // map_value
+      case 217: // db_type
+      case 293: // hr_mode
+      case 416: // duid_type
+      case 449: // ncr_protocol_value
+      case 457: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 152: // "boolean"
+      case 153: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 151: // "floating point"
+      case 152: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 150: // "integer"
+      case 151: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 149: // "constant string"
+      case 150: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1807,7 +1812,7 @@ namespace isc { namespace dhcp {
      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,   390,   391,   392,   393,   394,
      395,   396,   397,   398,   399,   400,   401,   402,   403,   404,
      395,   396,   397,   398,   399,   400,   401,   402,   403,   404,
-     405,   406,   407
+     405,   406,   407,   408
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -2671,6 +2676,12 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
+  Dhcp6Parser::make_SUB_OPTION_DEFS (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_SUB_OPTION_DEFS, l);
+  }
+
+  Dhcp6Parser::symbol_type
   Dhcp6Parser::make_SUB_OPTION_DEF (const location_type& l)
   Dhcp6Parser::make_SUB_OPTION_DEF (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_SUB_OPTION_DEF, l);
     return symbol_type (token::TOKEN_SUB_OPTION_DEF, l);
@@ -2721,7 +2732,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 2725 "dhcp6_parser.h" // lalr1.cc:377
+#line 2736 "dhcp6_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 66 - 5
src/bin/dhcp6/dhcp6_parser.yy

@@ -203,6 +203,7 @@ using namespace std;
   SUB_POOL6
   SUB_POOL6
   SUB_PD_POOL
   SUB_PD_POOL
   SUB_RESERVATION
   SUB_RESERVATION
+  SUB_OPTION_DEFS
   SUB_OPTION_DEF
   SUB_OPTION_DEF
   SUB_OPTION_DATA
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_HOOKS_LIBRARY
@@ -239,6 +240,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_POOL6 { ctx.ctx_ = ctx.POOLS; } sub_pool6
      | SUB_POOL6 { ctx.ctx_ = ctx.POOLS; } sub_pool6
      | SUB_PD_POOL { ctx.ctx_ = ctx.PD_POOLS; } sub_pd_pool
      | SUB_PD_POOL { ctx.ctx_ = ctx.PD_POOLS; } sub_pd_pool
      | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
      | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
+     | SUB_OPTION_DEFS { ctx.ctx_ = ctx.DHCP6; } sub_option_def_list
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
@@ -360,6 +362,9 @@ syntax_map: LCURLY_BRACKET {
     // map parsing completed. If we ever want to do any wrap up
     // map parsing completed. If we ever want to do any wrap up
     // (maybe some sanity checking), this would be the best place
     // (maybe some sanity checking), this would be the best place
     // for it.
     // for it.
+
+    // Dhcp6 is required
+    ctx.require("Dhcp6", ctx.loc2pos(@1), ctx.loc2pos(@4));
 };
 };
 
 
 // This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
 // This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
@@ -384,9 +389,7 @@ dhcp6_object: DHCP6 {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP6);
     ctx.enter(ctx.DHCP6);
 } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
-    // map parsing completed. If we ever want to do any wrap up
-    // (maybe some sanity checking), this would be the best place
-    // for it.
+    // No global parameter is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -398,6 +401,7 @@ sub_dhcp6: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } global_params RCURLY_BRACKET {
 } global_params RCURLY_BRACKET {
+    // No global parameter is required
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -462,6 +466,7 @@ interfaces_config: INTERFACES_CONFIG {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.INTERFACES_CONFIG);
     ctx.enter(ctx.INTERFACES_CONFIG);
 } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
+    // No interfaces config param is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -471,6 +476,7 @@ sub_interfaces6: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } interfaces_config_params RCURLY_BRACKET {
 } interfaces_config_params RCURLY_BRACKET {
+    // No interfaces config param is required
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -504,6 +510,8 @@ lease_database: LEASE_DATABASE {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.LEASE_DATABASE);
     ctx.enter(ctx.LEASE_DATABASE);
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+    // The type parameter is required
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -514,6 +522,8 @@ hosts_database: HOSTS_DATABASE {
     ctx.stack_.push_back(i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.HOSTS_DATABASE);
     ctx.enter(ctx.HOSTS_DATABASE);
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+    // The type parameter is required
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -716,6 +726,8 @@ hooks_library: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } hooks_params RCURLY_BRACKET {
 } hooks_params RCURLY_BRACKET {
+    // The library hooks parameter is required
+    ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -724,6 +736,8 @@ sub_hooks_library: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } hooks_params RCURLY_BRACKET {
 } hooks_params RCURLY_BRACKET {
+    // The library hooks parameter is required
+    ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -758,6 +772,7 @@ expired_leases_processing: EXPIRED_LEASES_PROCESSING {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
     ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
 } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
+    // No expired lease parameter is required
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -852,6 +867,9 @@ subnet6: LCURLY_BRACKET {
     //         ctx.stack_.back()->set("renew-timer", renew);
     //         ctx.stack_.back()->set("renew-timer", renew);
     //     }
     //     }
     // }
     // }
+
+    // The subnet subnet6 parameter is required
+    ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -860,6 +878,8 @@ sub_subnet6: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } subnet6_params RCURLY_BRACKET {
 } subnet6_params RCURLY_BRACKET {
+    // The subnet subnet6 parameter is required
+    ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -956,6 +976,16 @@ option_def_list: OPTION_DEF {
     ctx.leave();
     ctx.leave();
 };
 };
 
 
+// This defines the top level scope when the parser is told to parse
+// option definitions. It works as a subset limited to option
+// definitions
+sub_option_def_list: LCURLY_BRACKET {
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} option_def_list RCURLY_BRACKET {
+    // parsing completed
+};
+
 // This defines the content of option-def. It may be empty,
 // This defines the content of option-def. It may be empty,
 // have one entry or multiple entries separated by comma.
 // have one entry or multiple entries separated by comma.
 option_def_list_content: %empty
 option_def_list_content: %empty
@@ -973,6 +1003,10 @@ option_def_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_def_params RCURLY_BRACKET {
 } option_def_params RCURLY_BRACKET {
+    // The name, code and type option def parameters are required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -984,6 +1018,10 @@ sub_option_def: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_def_params RCURLY_BRACKET {
 } option_def_params RCURLY_BRACKET {
+    // The name, code and type option def parameters are required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1088,6 +1126,7 @@ option_data_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_data_params RCURLY_BRACKET {
 } option_data_params RCURLY_BRACKET {
+    /// @todo: the code or name parameters are required.
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1099,6 +1138,7 @@ sub_option_data: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } option_data_params RCURLY_BRACKET {
 } option_data_params RCURLY_BRACKET {
+    /// @todo: the code or name parameters are required.
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1178,6 +1218,8 @@ pool_list_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pool_params RCURLY_BRACKET {
 } pool_params RCURLY_BRACKET {
+    // The pool parameter is required.
+    ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1186,7 +1228,8 @@ sub_pool6: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pool_params RCURLY_BRACKET {
 } pool_params RCURLY_BRACKET {
-    // parsing completed
+    // The pool parameter is required.
+    ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
 };
 };
 
 
 pool_params: pool_param
 pool_params: pool_param
@@ -1242,6 +1285,10 @@ pd_pool_entry: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pd_pool_params RCURLY_BRACKET {
 } pd_pool_params RCURLY_BRACKET {
+    // The prefix, prefix len and delegated len parameters are required.
+    ctx.require("prefix", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("prefix-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("delegated-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1250,6 +1297,10 @@ sub_pd_pool: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } pd_pool_params RCURLY_BRACKET {
 } pd_pool_params RCURLY_BRACKET {
+    // The prefix, prefix len and delegated len parameters are required.
+    ctx.require("prefix", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("prefix-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
+    ctx.require("delegated-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1324,6 +1375,7 @@ reservation: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } reservation_params RCURLY_BRACKET {
 } reservation_params RCURLY_BRACKET {
+    /// @todo: an identifier parameter is required.
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1332,6 +1384,7 @@ sub_reservation: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } reservation_params RCURLY_BRACKET {
 } reservation_params RCURLY_BRACKET {
+    /// @todo: an identifier parameter is required.
     // parsing completed
     // parsing completed
 };
 };
 
 
@@ -1343,7 +1396,7 @@ not_empty_reservation_params: reservation_param
     | not_empty_reservation_params COMMA reservation_param
     | not_empty_reservation_params COMMA reservation_param
     ;
     ;
 
 
-// @todo probably need to add mac-address as well here
+/// @todo probably need to add mac-address as well here
 reservation_param: duid
 reservation_param: duid
                  | reservation_client_classes
                  | reservation_client_classes
                  | ip_addresses
                  | ip_addresses
@@ -1460,6 +1513,8 @@ client_class: LCURLY_BRACKET {
     ctx.stack_.back()->add(m);
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } client_class_params RCURLY_BRACKET {
 } client_class_params RCURLY_BRACKET {
+    // The name client class parameter is required.
+    ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
 };
 };
 
 
@@ -1496,6 +1551,8 @@ server_id: SERVER_ID {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.SERVER_ID);
     ctx.enter(ctx.SERVER_ID);
 } COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET {
+    // The type parameter is required.
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -1599,6 +1656,8 @@ dhcp_ddns: DHCP_DDNS {
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP_DDNS);
     ctx.enter(ctx.DHCP_DDNS);
 } COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
 } COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
+    // The enable updates DHCP DDNS parameter is required.
+    ctx.require("enable-updates", ctx.loc2pos(@4), ctx.loc2pos(@6));
     ctx.stack_.pop_back();
     ctx.stack_.pop_back();
     ctx.leave();
     ctx.leave();
 };
 };
@@ -1608,6 +1667,8 @@ sub_dhcp_ddns: LCURLY_BRACKET {
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.push_back(m);
     ctx.stack_.push_back(m);
 } dhcp_ddns_params RCURLY_BRACKET {
 } dhcp_ddns_params RCURLY_BRACKET {
+    // The enable updates DHCP DDNS parameter is required.
+    ctx.require("enable-updates", ctx.loc2pos(@1), ctx.loc2pos(@4));
     // parsing completed
     // parsing completed
 };
 };
 
 

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

@@ -1,4 +1,4 @@
-// Generated 201708070754
+// Generated 201709021237
 // 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++

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

@@ -95,6 +95,21 @@ Parser6Context::loc2pos(isc::dhcp::location& loc)
 }
 }
 
 
 void
 void
+Parser6Context::require(const std::string& name,
+                        isc::data::Element::Position open_loc,
+                        isc::data::Element::Position close_loc)
+{
+    ConstElementPtr value = stack_.back()->get(name);
+    if (!value) {
+        isc_throw(Dhcp6ParseError,
+                  "missing parameter '" << name << "' ("
+                  << stack_.back()->getPosition() << ") ["
+                  << contextName() << " map between "
+                  << open_loc << " and " << close_loc << "]");
+    }
+}
+
+void
 Parser6Context::enter(const ParserContext& ctx)
 Parser6Context::enter(const ParserContext& ctx)
 {
 {
     cstack_.push_back(ctx_);
     cstack_.push_back(ctx_);

+ 16 - 0
src/bin/dhcp6/parser_context.h

@@ -76,6 +76,9 @@ public:
         /// This will parse the input as host-reservation.
         /// This will parse the input as host-reservation.
         PARSER_HOST_RESERVATION,
         PARSER_HOST_RESERVATION,
 
 
+        /// This will parse the input option definitions (for tests).
+        PARSER_OPTION_DEFS,
+
         /// This will parse the input as option definition.
         /// This will parse the input as option definition.
         PARSER_OPTION_DEF,
         PARSER_OPTION_DEF,
 
 
@@ -179,6 +182,19 @@ public:
     /// @return Position in format accepted by Element
     /// @return Position in format accepted by Element
     isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
     isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
 
 
+    /// @brief Check if a required parameter is present
+    ///
+    /// Check if a required parameter is present in the map at the top
+    /// of the stack and raise an error when it is not.
+    ///
+    /// @param name name of the parameter expected to be present
+    /// @param open_loc location of the opening curly bracket
+    /// @param close_loc ocation of the closing curly bracket
+    /// @throw Dhcp6ParseError
+    void require(const std::string& name,
+                 isc::data::Element::Position open_loc,
+                 isc::data::Element::Position close_loc);
+
     /// @brief Defines syntactic contexts for lexical tie-ins
     /// @brief Defines syntactic contexts for lexical tie-ins
     typedef enum {
     typedef enum {
         ///< This one is used in pure JSON mode.
         ///< This one is used in pure JSON mode.

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

@@ -1,4 +1,4 @@
-// Generated 201708070754
+// Generated 201709021237
 // 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 201708070754
+// Generated 201709021237
 // 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++

+ 25 - 20
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -1998,7 +1998,13 @@ TEST_F(Dhcp6ParserTest, invalidPdPools) {
     int num_msgs = sizeof(config)/sizeof(char*);
     int num_msgs = sizeof(config)/sizeof(char*);
     for (unsigned int i = 0; i < num_msgs; i++) {
     for (unsigned int i = 0; i < num_msgs; i++) {
         // Convert JSON string to Elements.
         // Convert JSON string to Elements.
-        ASSERT_NO_THROW(json = parseDHCP6(config[i]));
+        // The 3 first configs should fail to parse.
+        if (i < 3) {
+            EXPECT_THROW(parseDHCP6(config[i]), Dhcp6ParseError);
+            json = parseJSON(config[i]);
+        } else {
+            ASSERT_NO_THROW(json = parseDHCP6(config[i]));
+        }
 
 
         // Configuration processing should fail without a throw.
         // Configuration processing should fail without a throw.
         ASSERT_NO_THROW(x = configureDhcp6Server(srv_, json));
         ASSERT_NO_THROW(x = configureDhcp6Server(srv_, json));
@@ -2024,7 +2030,7 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -2064,9 +2070,8 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
 
 
     // Let's apply empty configuration. This removes the option definitions
     // Let's apply empty configuration. This removes the option definitions
     // configuration and should result in removal of the option 100 from the
     // configuration and should result in removal of the option 100 from the
-    // libdhcp++.
-    config = "{ }";
-    json = parseOPTION_DEF(config);
+    // libdhcp++. Note DHCP6 or OPTION_DEFS parsers do not accept empty maps.
+    json.reset(new MapElement());
     ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
     ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
     checkResult(status, 0);
     checkResult(status, 0);
 
 
@@ -2089,7 +2094,7 @@ TEST_F(Dhcp6ParserTest, optionDefRecord) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -2143,7 +2148,7 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the option definitions do not exist yet.
     // Make sure that the option definitions do not exist yet.
@@ -2211,7 +2216,7 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Make sure that the option definition does not exist yet.
     // Make sure that the option definition does not exist yet.
     ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
     ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
@@ -2250,7 +2255,7 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -2291,7 +2296,7 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulate) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
     extractConfig(config);
     extractConfig(config);
 
 
     // Make sure that the particular option definition does not exist.
     // Make sure that the particular option definition does not exist.
@@ -2331,7 +2336,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2356,7 +2361,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidType) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2382,7 +2387,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2408,7 +2413,7 @@ TEST_F(Dhcp6ParserTest, optionIntegerTypes) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2434,7 +2439,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidEncapsulatedSpace) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2463,7 +2468,7 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulatedSpaceAndArray) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2489,7 +2494,7 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulateOwnSpace) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     ConstElementPtr status;
     ConstElementPtr status;
@@ -2519,7 +2524,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
         "  } ]"
         "  } ]"
         "}";
         "}";
     ConstElementPtr json;
     ConstElementPtr json;
-    ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+    ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
 
 
     OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
     OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
         getCfgOptionDef()->get(DHCP6_OPTION_SPACE, 100);
         getCfgOptionDef()->get(DHCP6_OPTION_SPACE, 100);
@@ -2553,7 +2558,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
         "      \"space\": \"dhcp6\""
         "      \"space\": \"dhcp6\""
         "  } ]"
         "  } ]"
         "}";
         "}";
-    json = parseOPTION_DEF(config);
+    json = parseOPTION_DEFS(config);
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
@@ -2575,7 +2580,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
         "      \"space\": \"dhcp6\""
         "      \"space\": \"dhcp6\""
         "  } ]"
         "  } ]"
         "}";
         "}";
-    json = parseOPTION_DEF(config);
+    json = parseOPTION_DEFS(config);
 
 
     // Use the configuration string to create new option definition.
     // Use the configuration string to create new option definition.
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));

+ 2 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -696,11 +696,11 @@ parseDHCP6(const std::string& in, bool verbose = false)
 /// @param verbose display the exception message when it fails
 /// @param verbose display the exception message when it fails
 /// @return ElementPtr structure representing parsed JSON
 /// @return ElementPtr structure representing parsed JSON
 inline isc::data::ElementPtr
 inline isc::data::ElementPtr
-parseOPTION_DEF(const std::string& in, bool verbose = false)
+parseOPTION_DEFS(const std::string& in, bool verbose = false)
 {
 {
     try {
     try {
         isc::dhcp::Parser6Context ctx;
         isc::dhcp::Parser6Context ctx;
-        return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEF));
+        return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEFS));
     }
     }
     catch (const std::exception& ex) {
     catch (const std::exception& ex) {
         if (verbose) {
         if (verbose) {

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

@@ -506,6 +506,13 @@ TEST(ParserTest, errors) {
               Parser6Context::PARSER_DHCP6,
               Parser6Context::PARSER_DHCP6,
               "<string>:2.2-21: got unexpected keyword "
               "<string>:2.2-21: got unexpected keyword "
               "\"preferred_lifetime\" in Dhcp6 map.");
               "\"preferred_lifetime\" in Dhcp6 map.");
+
+    // missing parameter
+    testError("{ \"name\": \"foo\",\n"
+              "  \"code\": 123 }\n",
+              Parser6Context::PARSER_OPTION_DEF,
+              "missing parameter 'type' (<string>:1:1) "
+              "[option-def map between <string>:1:1 and <string>:2:15]");
 }
 }
 
 
 // Check unicode escapes
 // Check unicode escapes