]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#260,!20] Packet queueing is now optional
authorThomas Markwalder <tmark@isc.org>
Sat, 10 Nov 2018 18:20:22 +0000 (13:20 -0500)
committerThomas Markwalder <tmark@isc.org>
Sat, 10 Nov 2018 18:20:22 +0000 (13:20 -0500)
src/bin/dhcp<4/6>/ctrl_dhcp<4/6>_srv.cc
    ControlledDhcpv<4/6>Srv::processConfig() - now calls
        IfaceMgr::configureDHCPPacketQueue

src/bin/dhcp<4/6>/dhcp<4/6>_parser.yy
    dhpc-queue-control parsing updated to enforce
    enable-queue/queue-type rules

src/bin/dhcp<4/6>/tests/config_parser_unittest.cc
    TEST_F(Dhcp<4/6>ParserTest, dhcpQueueControl)
    TEST_F(Dhcp<4/6>ParserTest, dhcpQueueControlInvalid)

src/lib/dhcp/iface_mgr.*
    IfaceMgr
    - closeSockets()  - now calls stopDHCPReceiver

    - openSockets<4/6>() -  now calls startDHCPReceiver

    - receive<4/6>Indirect() - new function which monitors receiver
    thread watch sockets, reads DHCP packets from queue

    - receive<4/6>Direct() - new function which monitors and reads DHCP
    packets from interface sockets directly

    - receive<4/6>() - rewritten to call receive<4/6>Indirect
    if receiver thread is running, otherwise it calls receive<4/6>Direct

    - configureDHCPPacketQueue() - new function which either enables queuing
    by creating a new packet queue, or disables it by destroying the
    existing queue

src/lib/dhcp/packet_queue_mgr.h
    PacketQueue::destroyPacketQueue() - new function

src/lib/dhcp/packet_queue_mgr<4/6>.cc
    PacketQueueMgr<4/6>::PacketQueueMgr<4/6>() - no longer creates a
    default packet queue

src/lib/dhcpsrv/cfg_iface.cc
    CfgIface::closeSockets() - removed call to stopDHCPReceiver
    CfgIface::openSockets() - removed call to startDHCPReceiver

src/lib/dhcpsrv/parsers/dhcp_queue_control_parser.*
    DHCPQueueControlParser
    - removed unused family_ member
    - parse() - added support for enable-queue

src/lib/dhcpsrv/tests/dhcp_queue_control_parser_unittest.cc
    - new file

25 files changed:
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/dhcp4_parser.cc
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/bin/dhcp6/dhcp6_parser.cc
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/lib/dhcp/iface_mgr.cc
src/lib/dhcp/iface_mgr.h
src/lib/dhcp/packet_queue_mgr.h
src/lib/dhcp/packet_queue_mgr4.cc
src/lib/dhcp/packet_queue_mgr4.h
src/lib/dhcp/packet_queue_mgr6.cc
src/lib/dhcp/packet_queue_mgr6.h
src/lib/dhcp/tests/iface_mgr_unittest.cc
src/lib/dhcp/tests/packet_queue_mgr4_unittest.cc
src/lib/dhcp/tests/packet_queue_mgr6_unittest.cc
src/lib/dhcpsrv/cfg_iface.cc
src/lib/dhcpsrv/parsers/dhcp_queue_control_parser.cc
src/lib/dhcpsrv/parsers/dhcp_queue_control_parser.h
src/lib/dhcpsrv/tests/Makefile.am
src/lib/dhcpsrv/tests/dhcp_queue_control_parser_unittest.cc [new file with mode: 0644]

index 20b78029b718088b551a6e394b8bbbdf6324bbc1..b78154bc5584a80b4dd95c58e63c7af975213eb1 100644 (file)
@@ -634,24 +634,15 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
         return (isc::config::createAnswer(1, err.str()));
     }
 
-    // Configure packet queue
+    // Configure DHCP packet queueing
     try {
         data::ConstElementPtr qc;
         qc  = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
-        if (!qc) {
-            // @todo For now we're manually constructing default queue config
-            // This probably needs to be built into the PQM?
-            data::ElementPtr default_qc = data::Element::createMap();
-            default_qc->set("queue-type", data::Element::create("kea-ring4"));
-            default_qc->set("capacity", data::Element::create(static_cast<long int>(500)));
-            PacketQueueMgr4::instance().createPacketQueue(default_qc);
-        } else {
-            PacketQueueMgr4::instance().createPacketQueue(qc);
+        if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
+            LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CONFIG_PACKET_QUEUE)
+                      .arg(PacketQueueMgr4::instance().getPacketQueue()->getInfoStr());
         }
 
-        LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CONFIG_PACKET_QUEUE)
-                 .arg(PacketQueueMgr4::instance().getPacketQueue()->getInfoStr());
-
     } catch (const std::exception& ex) {
         err << "Error setting packet queue controls after server reconfiguration: "
             << ex.what();
index 3f883f5bcf237f587625436f92bd4a04d4e041ba..97942a4f9df0f724464cc6f1002d669e73a9066a 100644 (file)
@@ -2980,653 +2980,680 @@ namespace isc { namespace dhcp {
     ElementPtr qc = yystack_[0].value.as< ElementPtr > ();
     ctx.stack_.back()->set("dhcp-queue-control", qc);
 
-    if (!qc->contains("queue-type")) {
+    // Doing this manually, because dhcp-queue-control
+    // content is otherwise arbitrary
+    if (!qc->contains("enable-queue")) {
         std::stringstream msg;
-        msg << "'queue-type' is required: ";
+        msg << "'enable-queue' is required: ";
         msg  << qc->getPosition().str() << ")";
         error(yystack_[3].location, msg.str());
     }
 
+     ConstElementPtr enable_queue = qc->get("enable-queue");
+     if (enable_queue->getType() != Element::boolean) {
+        std::stringstream msg;
+        msg << "'enable-queue' must be boolean: ";
+        msg  << qc->getPosition().str() << ")";
+        error(yystack_[3].location, msg.str());
+     }
+
+    if (enable_queue->boolValue()) {
+        if (!qc->contains("queue-type")) {
+            std::stringstream msg;
+            msg << "'queue-type' is required, when 'enable-queue' is true: ";
+            msg  << qc->getPosition().str() << ")";
+            error(yystack_[3].location, msg.str());
+        }
+
+        ConstElementPtr queue_type = qc->get("queue-type");
+        if (queue_type->getType() != Element::string) {
+            std::stringstream msg;
+            msg << "'queue-type' must be a string: ";
+            msg  << qc->getPosition().str() << ")";
+            error(yystack_[3].location, msg.str());
+        }
+     }
+
     ctx.leave();
 }
-#line 2993 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3020 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 534:
-#line 1859 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1886 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP_DDNS);
 }
-#line 3004 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3031 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 535:
-#line 1864 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1891 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // The enable updates DHCP DDNS parameter is required.
     ctx.require("enable-updates", ctx.loc2pos(yystack_[2].location), ctx.loc2pos(yystack_[0].location));
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3015 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3042 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 536:
-#line 1871 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1898 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // Parse the dhcp-ddns map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3025 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3052 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 537:
-#line 1875 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1902 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // The enable updates DHCP DDNS parameter is required.
     ctx.require("enable-updates", ctx.loc2pos(yystack_[3].location), ctx.loc2pos(yystack_[0].location));
     // parsing completed
 }
-#line 3035 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3062 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 559:
-#line 1906 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1933 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("enable-updates", b);
 }
-#line 3044 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3071 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 560:
-#line 1911 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1938 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3052 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3079 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 561:
-#line 1913 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1940 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("qualifying-suffix", s);
     ctx.leave();
 }
-#line 3062 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3089 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 562:
-#line 1919 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1946 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3070 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3097 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 563:
-#line 1921 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1948 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("server-ip", s);
     ctx.leave();
 }
-#line 3080 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3107 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 564:
-#line 1927 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1954 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("server-port", i);
 }
-#line 3089 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3116 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 565:
-#line 1932 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1959 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3097 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3124 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 566:
-#line 1934 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1961 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("sender-ip", s);
     ctx.leave();
 }
-#line 3107 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3134 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 567:
-#line 1940 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1967 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("sender-port", i);
 }
-#line 3116 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3143 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 568:
-#line 1945 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1972 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("max-queue-size", i);
 }
-#line 3125 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3152 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 569:
-#line 1950 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1977 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NCR_PROTOCOL);
 }
-#line 3133 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3160 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 570:
-#line 1952 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1979 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("ncr-protocol", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3142 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3169 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 571:
-#line 1958 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1985 "dhcp4_parser.yy" // lalr1.cc:859
     { yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("UDP", ctx.loc2pos(yystack_[0].location))); }
-#line 3148 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3175 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 572:
-#line 1959 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1986 "dhcp4_parser.yy" // lalr1.cc:859
     { yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("TCP", ctx.loc2pos(yystack_[0].location))); }
-#line 3154 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3181 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 573:
-#line 1962 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1989 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NCR_FORMAT);
 }
-#line 3162 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3189 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 574:
-#line 1964 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1991 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr json(new StringElement("JSON", ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("ncr-format", json);
     ctx.leave();
 }
-#line 3172 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3199 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 575:
-#line 1970 "dhcp4_parser.yy" // lalr1.cc:859
+#line 1997 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("always-include-fqdn", b);
 }
-#line 3181 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3208 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 576:
-#line 1975 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2002 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("override-no-update", b);
 }
-#line 3190 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3217 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 577:
-#line 1980 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2007 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("override-client-update", b);
 }
-#line 3199 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3226 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 578:
-#line 1985 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2012 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.REPLACE_CLIENT_NAME);
 }
-#line 3207 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3234 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 579:
-#line 1987 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2014 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("replace-client-name", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3216 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3243 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 580:
-#line 1993 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2020 "dhcp4_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("when-present", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3224 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3251 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 581:
-#line 1996 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2023 "dhcp4_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("never", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3232 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3259 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 582:
-#line 1999 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2026 "dhcp4_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("always", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3240 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3267 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 583:
-#line 2002 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2029 "dhcp4_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("when-not-present", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3248 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3275 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 584:
-#line 2005 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2032 "dhcp4_parser.yy" // lalr1.cc:859
     {
       error(yystack_[0].location, "boolean values for the replace-client-name are "
                 "no longer supported");
       }
-#line 3257 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3284 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 585:
-#line 2011 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2038 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3265 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3292 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 586:
-#line 2013 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2040 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("generated-prefix", s);
     ctx.leave();
 }
-#line 3275 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3302 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 587:
-#line 2019 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2046 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3283 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3310 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 588:
-#line 2021 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2048 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("hostname-char-set", s);
     ctx.leave();
 }
-#line 3293 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3320 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 589:
-#line 2027 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2054 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3301 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3328 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 590:
-#line 2029 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2056 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("hostname-char-replacement", s);
     ctx.leave();
 }
-#line 3311 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3338 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 591:
-#line 2038 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2065 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3319 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3346 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 592:
-#line 2040 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2067 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("Dhcp6", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3328 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3355 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 593:
-#line 2045 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2072 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3336 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3363 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 594:
-#line 2047 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2074 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("DhcpDdns", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3345 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3372 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 595:
-#line 2052 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2079 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3353 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3380 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 596:
-#line 2054 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2081 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("Control-agent", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3362 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3389 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 597:
-#line 2059 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2086 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
 }
-#line 3372 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3399 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 598:
-#line 2063 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2090 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3380 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3407 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 599:
-#line 2068 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2095 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("config-control", i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.CONFIG_CONTROL);
 }
-#line 3391 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3418 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 600:
-#line 2073 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2100 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // No config control params are required
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3401 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3428 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 601:
-#line 2079 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2106 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // Parse the config-control map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3411 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3438 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 602:
-#line 2083 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2110 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // No config_control params are required
     // parsing completed
 }
-#line 3420 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3447 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 607:
-#line 2098 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2125 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("config-databases", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.CONFIG_DATABASE);
 }
-#line 3431 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3458 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 608:
-#line 2103 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2130 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3440 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3467 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 609:
-#line 2113 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2140 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("Logging", m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.LOGGING);
 }
-#line 3451 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3478 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 610:
-#line 2118 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2145 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3460 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3487 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 611:
-#line 2123 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2150 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // Parse the Logging map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3470 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3497 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 612:
-#line 2127 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2154 "dhcp4_parser.yy" // lalr1.cc:859
     {
     // parsing completed
 }
-#line 3478 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3505 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 616:
-#line 2143 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2170 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("loggers", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.LOGGERS);
 }
-#line 3489 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3516 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 617:
-#line 2148 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2175 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3498 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3525 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 620:
-#line 2160 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2187 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(l);
     ctx.stack_.push_back(l);
 }
-#line 3508 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3535 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 621:
-#line 2164 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2191 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3516 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3543 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 631:
-#line 2181 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2208 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr dl(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("debuglevel", dl);
 }
-#line 3525 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3552 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 632:
-#line 2186 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2213 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3533 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3560 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 633:
-#line 2188 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2215 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr sev(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("severity", sev);
     ctx.leave();
 }
-#line 3543 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3570 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 634:
-#line 2194 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2221 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("output_options", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.OUTPUT_OPTIONS);
 }
-#line 3554 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3581 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 635:
-#line 2199 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2226 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3563 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3590 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 638:
-#line 2208 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2235 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
 }
-#line 3573 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3600 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 639:
-#line 2212 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2239 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3581 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3608 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 646:
-#line 2226 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2253 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3589 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3616 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 647:
-#line 2228 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2255 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr sev(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("output", sev);
     ctx.leave();
 }
-#line 3599 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3626 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 648:
-#line 2234 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2261 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr flush(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("flush", flush);
 }
-#line 3608 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3635 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 649:
-#line 2239 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2266 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr maxsize(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("maxsize", maxsize);
 }
-#line 3617 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3644 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
   case 650:
-#line 2244 "dhcp4_parser.yy" // lalr1.cc:859
+#line 2271 "dhcp4_parser.yy" // lalr1.cc:859
     {
     ElementPtr maxver(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("maxver", maxver);
 }
-#line 3626 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3653 "dhcp4_parser.cc" // lalr1.cc:859
     break;
 
 
-#line 3630 "dhcp4_parser.cc" // lalr1.cc:859
+#line 3657 "dhcp4_parser.cc" // lalr1.cc:859
             default:
               break;
             }
@@ -4857,19 +4884,19 @@ namespace isc { namespace dhcp {
     1755,  1758,  1759,  1762,  1763,  1764,  1765,  1766,  1767,  1768,
     1769,  1770,  1771,  1772,  1775,  1777,  1777,  1785,  1794,  1801,
     1801,  1811,  1812,  1815,  1816,  1817,  1818,  1819,  1822,  1822,
-    1830,  1830,  1841,  1841,  1859,  1859,  1871,  1871,  1881,  1882,
-    1885,  1886,  1887,  1888,  1889,  1890,  1891,  1892,  1893,  1894,
-    1895,  1896,  1897,  1898,  1899,  1900,  1901,  1902,  1903,  1906,
-    1911,  1911,  1919,  1919,  1927,  1932,  1932,  1940,  1945,  1950,
-    1950,  1958,  1959,  1962,  1962,  1970,  1975,  1980,  1985,  1985,
-    1993,  1996,  1999,  2002,  2005,  2011,  2011,  2019,  2019,  2027,
-    2027,  2038,  2038,  2045,  2045,  2052,  2052,  2059,  2059,  2068,
-    2068,  2079,  2079,  2089,  2090,  2094,  2095,  2098,  2098,  2113,
-    2113,  2123,  2123,  2134,  2135,  2139,  2143,  2143,  2155,  2156,
-    2160,  2160,  2168,  2169,  2172,  2173,  2174,  2175,  2176,  2177,
-    2178,  2181,  2186,  2186,  2194,  2194,  2204,  2205,  2208,  2208,
-    2216,  2217,  2220,  2221,  2222,  2223,  2226,  2226,  2234,  2239,
-    2244
+    1830,  1830,  1841,  1841,  1886,  1886,  1898,  1898,  1908,  1909,
+    1912,  1913,  1914,  1915,  1916,  1917,  1918,  1919,  1920,  1921,
+    1922,  1923,  1924,  1925,  1926,  1927,  1928,  1929,  1930,  1933,
+    1938,  1938,  1946,  1946,  1954,  1959,  1959,  1967,  1972,  1977,
+    1977,  1985,  1986,  1989,  1989,  1997,  2002,  2007,  2012,  2012,
+    2020,  2023,  2026,  2029,  2032,  2038,  2038,  2046,  2046,  2054,
+    2054,  2065,  2065,  2072,  2072,  2079,  2079,  2086,  2086,  2095,
+    2095,  2106,  2106,  2116,  2117,  2121,  2122,  2125,  2125,  2140,
+    2140,  2150,  2150,  2161,  2162,  2166,  2170,  2170,  2182,  2183,
+    2187,  2187,  2195,  2196,  2199,  2200,  2201,  2202,  2203,  2204,
+    2205,  2208,  2213,  2213,  2221,  2221,  2231,  2232,  2235,  2235,
+    2243,  2244,  2247,  2248,  2249,  2250,  2253,  2253,  2261,  2266,
+    2271
   };
 
   // Print the state stack on the debug stream.
@@ -4904,8 +4931,8 @@ namespace isc { namespace dhcp {
 
 #line 14 "dhcp4_parser.yy" // lalr1.cc:1167
 } } // isc::dhcp
-#line 4908 "dhcp4_parser.cc" // lalr1.cc:1167
-#line 2249 "dhcp4_parser.yy" // lalr1.cc:1168
+#line 4935 "dhcp4_parser.cc" // lalr1.cc:1167
+#line 2276 "dhcp4_parser.yy" // lalr1.cc:1168
 
 
 void
index e18fc6658492de0eb91ebc5808344de458585cac..0bf3ea9df166511a43e92da37cf1e996e7090976 100644 (file)
@@ -1844,13 +1844,40 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL {
     ElementPtr qc = $4;
     ctx.stack_.back()->set("dhcp-queue-control", qc);
 
-    if (!qc->contains("queue-type")) {
+    // Doing this manually, because dhcp-queue-control
+    // content is otherwise arbitrary
+    if (!qc->contains("enable-queue")) {
         std::stringstream msg;
-        msg << "'queue-type' is required: ";
+        msg << "'enable-queue' is required: ";
         msg  << qc->getPosition().str() << ")";
         error(@1, msg.str());
     }
 
+     ConstElementPtr enable_queue = qc->get("enable-queue");
+     if (enable_queue->getType() != Element::boolean) {
+        std::stringstream msg;
+        msg << "'enable-queue' must be boolean: ";
+        msg  << qc->getPosition().str() << ")";
+        error(@1, msg.str());
+     }
+
+    if (enable_queue->boolValue()) {
+        if (!qc->contains("queue-type")) {
+            std::stringstream msg;
+            msg << "'queue-type' is required, when 'enable-queue' is true: ";
+            msg  << qc->getPosition().str() << ")";
+            error(@1, msg.str());
+        }
+
+        ConstElementPtr queue_type = qc->get("queue-type");
+        if (queue_type->getType() != Element::string) {
+            std::stringstream msg;
+            msg << "'queue-type' must be a string: ";
+            msg  << qc->getPosition().str() << ")";
+            error(@1, msg.str());
+        }
+     }
+
     ctx.leave();
 };
 
index 913ff50a23a413ccf6f35293da64a1d1e7741f11..8fa2e1f142e192eeffa2d22350fc28a0bbf56880 100644 (file)
@@ -391,7 +391,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
             }
 
             if (config_pair.first == "dhcp-queue-control") {
-                DHCPQueueControlParser parser(AF_INET);
+                DHCPQueueControlParser parser;
                 srv_cfg->setDHCPQueueControl(parser.parse(config_pair.second));
                 continue;
             }
index 4c8ba4148d5019fbbc9daf3054d2a7e383755f58..bc66dd4eed162e75c7164b5c07066c61c66dbea1 100644 (file)
@@ -6437,20 +6437,33 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControl) {
         ""
         },
         {
-        "valid entry",
+        "queue disabled",
         "{ \n"
-        "   \"queue-type\": \"some-type\", \n"
-        "   \"capacity\": 75 \n"
+        "   \"enable-queue\": false \n"
+        "} \n"
+        },
+        {
+        "queue disabled, arbitrary content allowed",
+        "{ \n"
+        "   \"enable-queue\": false, \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
+        "} \n"
+        },
+        {
+        "queue enabled, with queue-type",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\" \n"
         "} \n"
         },
         {
-        "valid arbitrary content",
+        "queue enabled with queue-type and arbitrary content",
         "{ \n"
-        "       \"queue-type\": \"some-type\", \n"
-        "       \"capacity\": 90, \n"
-        "       \"user-context\": { \"comment\": \"some text\" },\n"
-        "       \"random-bool\" : false, \n"
-        "       \"random-int\" : 1234 \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\", \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
         "} \n"
         }
     };
@@ -6460,9 +6473,7 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControl) {
     control = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
     ASSERT_FALSE(control);
 
-    // Iterate over the incorrect scenarios and verify they
-    // fail as expected. Note, we use parseDHCP4() directly
-    // as all of the errors above are enforced by the grammar.
+    // Iterate over the valid scenarios and verify they succeed.
     data::ConstElementPtr exp_elems;
     for (auto scenario : scenarios) {
         SCOPED_TRACE(scenario.description_);
@@ -6507,24 +6518,43 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) {
     struct Scenario {
         std::string description_;
         std::string json_;
+        std::string exp_error_;
     };
 
     std::vector<Scenario> scenarios = {
         {
-            "not a map",
-            "{ " + genIfaceConfig() + ", \n" +
-            "   \"subnet4\": [  ],  \n"
-            "   \"dhcp-queue-control\": 75 \n"
-            "} \n"
+        "not a map",
+        "75 \n",
+        "<string>:2.24-25: syntax error, unexpected integer, expecting {"
+        },
+        {
+        "enable-queue missing",
+        "{ \n"
+        "   \"enable-type\": \"some-type\" \n"
+        "} \n",
+        "<string>:2.2-21: 'enable-queue' is required: <string>:2:24)"
         },
         {
-            "queue type missing",
-            "{ " + genIfaceConfig() + ", \n" +
-            "   \"subnet4\": [  ],  \n"
-            "   \"dhcp-queue-control\": { \n"
-            "       \"capacity\": 100 \n"
-            "   } \n"
-            "} \n"
+        "enable-queue not boolean",
+        "{ \n"
+        "   \"enable-queue\": \"always\" \n"
+        "} \n",
+        "<string>:2.2-21: 'enable-queue' must be boolean: <string>:2:24)"
+        },
+        {
+        "queue enabled, type missing",
+        "{ \n"
+        "   \"enable-queue\": true \n"
+        "} \n",
+        "<string>:2.2-21: 'queue-type' is required, when 'enable-queue' is true: <string>:2:24)"
+        },
+        {
+        "queue enabled, type not a string",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": 7777 \n"
+        "} \n",
+        "<string>:2.2-21: 'queue-type' must be a string: <string>:2:24)"
         }
     };
 
@@ -6534,10 +6564,23 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) {
     for (auto scenario : scenarios) {
         SCOPED_TRACE(scenario.description_);
         {
-            EXPECT_THROW(parseDHCP4(scenario.json_), Dhcp4ParseError);
+            // Construct the config JSON
+            std::stringstream os;
+            os << "{ " + genIfaceConfig();
+            os << ",\n \"dhcp-queue-control\": "  <<  scenario.json_;
+            os << "} \n";
+
+            std::string error_msg = "";
+            try {
+                ASSERT_TRUE(parseDHCP4(os.str(), false)) << "parser returned empty element";
+            } catch(const std::exception& ex) {
+                error_msg = ex.what();
+            }
+
+            ASSERT_FALSE(error_msg.empty()) << "parseDHCP4 should have thrown";
+            EXPECT_EQ(scenario.exp_error_, error_msg);
         }
     }
 }
 
-
 }
index a7241c117075926aeaaee9d514437738aa92271e..08e6e2f65d6088d75a254390f98534d5f80ca9d5 100644 (file)
@@ -653,27 +653,18 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
         return (isc::config::createAnswer(1, err.str()));
     }
 
-    // Configure DHCP packet queue
+    // Configure DHCP packet queueing
     try {
         data::ConstElementPtr qc;
         qc  = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
-        if (!qc) {
-            // @todo For now we're manually constructing default queue config
-            // This probably needs to be built into the PQM?
-            data::ElementPtr default_qc = data::Element::createMap();
-            default_qc->set("queue-type", data::Element::create("kea-ring6"));
-            default_qc->set("capacity", data::Element::create(static_cast<long int>(500)));
-            PacketQueueMgr6::instance().createPacketQueue(default_qc);
-        } else {
-            PacketQueueMgr6::instance().createPacketQueue(qc);
+        if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CONFIG_PACKET_QUEUE)
+                      .arg(PacketQueueMgr6::instance().getPacketQueue()->getInfoStr());
         }
 
-        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CONFIG_PACKET_QUEUE)
-                 .arg(PacketQueueMgr6::instance().getPacketQueue()->getInfoStr());
-
     } catch (const std::exception& ex) {
         std::ostringstream err;
-        err << "Error setting DHCP packet queue controls after server reconfiguration: "
+        err << "Error setting packet queue controls after server reconfiguration: "
             << ex.what();
         return (isc::config::createAnswer(1, err.str()));
     }
index 3b6755872fa23edf9461a7ee6168546f3c70303c..0d8af522cf65c91ed666025e8429101a86e5bd4a 100644 (file)
@@ -3058,653 +3058,681 @@ namespace isc { namespace dhcp {
     ElementPtr qc = yystack_[0].value.as< ElementPtr > ();
     ctx.stack_.back()->set("dhcp-queue-control", qc);
 
-    if (!qc->contains("queue-type")) {
+    // Doing this manually, because dhcp-queue-control
+    // content is otherwise arbitrary
+    if (!qc->contains("enable-queue")) {
         std::stringstream msg;
-        msg << "'queue-type' is required: ";
+        msg << "'enable-queue' is required: ";
         msg  << qc->getPosition().str() << ")";
         error(yystack_[3].location, msg.str());
     }
 
+     ConstElementPtr enable_queue = qc->get("enable-queue");
+     if (enable_queue->getType() != Element::boolean) {
+        std::stringstream msg;
+        msg << "'enable-queue' must be boolean: ";
+        msg  << qc->getPosition().str() << ")";
+        error(yystack_[3].location, msg.str());
+     }
+
+    if (enable_queue->boolValue()) {
+        if (!qc->contains("queue-type")) {
+            std::stringstream msg;
+            msg << "'queue-type' is required, when 'enable-queue' is true: ";
+            msg  << qc->getPosition().str() << ")";
+            error(yystack_[3].location, msg.str());
+        }
+
+        ConstElementPtr queue_type = qc->get("queue-type");
+        if (queue_type->getType() != Element::string) {
+            std::stringstream msg;
+            msg << "'queue-type' must be a string: ";
+            msg  << qc->getPosition().str() << ")";
+            error(yystack_[3].location, msg.str());
+        }
+     }
+
+
     ctx.leave();
 }
-#line 3071 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3099 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 555:
-#line 1948 "dhcp6_parser.yy" // lalr1.cc:859
+#line 1976 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("dhcp-ddns", m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.DHCP_DDNS);
 }
-#line 3082 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3110 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 556:
-#line 1953 "dhcp6_parser.yy" // lalr1.cc:859
+#line 1981 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // The enable updates DHCP DDNS parameter is required.
     ctx.require("enable-updates", ctx.loc2pos(yystack_[2].location), ctx.loc2pos(yystack_[0].location));
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3093 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3121 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 557:
-#line 1960 "dhcp6_parser.yy" // lalr1.cc:859
+#line 1988 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // Parse the dhcp-ddns map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3103 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3131 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 558:
-#line 1964 "dhcp6_parser.yy" // lalr1.cc:859
+#line 1992 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // The enable updates DHCP DDNS parameter is required.
     ctx.require("enable-updates", ctx.loc2pos(yystack_[3].location), ctx.loc2pos(yystack_[0].location));
     // parsing completed
 }
-#line 3113 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3141 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 580:
-#line 1995 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2023 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("enable-updates", b);
 }
-#line 3122 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3150 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 581:
-#line 2000 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2028 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3130 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3158 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 582:
-#line 2002 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2030 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("qualifying-suffix", s);
     ctx.leave();
 }
-#line 3140 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3168 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 583:
-#line 2008 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2036 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3148 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3176 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 584:
-#line 2010 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2038 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("server-ip", s);
     ctx.leave();
 }
-#line 3158 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3186 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 585:
-#line 2016 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2044 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("server-port", i);
 }
-#line 3167 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3195 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 586:
-#line 2021 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2049 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3175 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3203 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 587:
-#line 2023 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2051 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("sender-ip", s);
     ctx.leave();
 }
-#line 3185 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3213 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 588:
-#line 2029 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2057 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("sender-port", i);
 }
-#line 3194 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3222 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 589:
-#line 2034 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2062 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("max-queue-size", i);
 }
-#line 3203 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3231 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 590:
-#line 2039 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2067 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NCR_PROTOCOL);
 }
-#line 3211 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3239 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 591:
-#line 2041 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2069 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("ncr-protocol", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3220 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3248 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 592:
-#line 2047 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2075 "dhcp6_parser.yy" // lalr1.cc:859
     { yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("UDP", ctx.loc2pos(yystack_[0].location))); }
-#line 3226 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3254 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 593:
-#line 2048 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2076 "dhcp6_parser.yy" // lalr1.cc:859
     { yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("TCP", ctx.loc2pos(yystack_[0].location))); }
-#line 3232 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3260 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 594:
-#line 2051 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2079 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NCR_FORMAT);
 }
-#line 3240 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3268 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 595:
-#line 2053 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2081 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr json(new StringElement("JSON", ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("ncr-format", json);
     ctx.leave();
 }
-#line 3250 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3278 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 596:
-#line 2059 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2087 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("always-include-fqdn", b);
 }
-#line 3259 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3287 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 597:
-#line 2064 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2092 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("override-no-update", b);
 }
-#line 3268 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3296 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 598:
-#line 2069 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2097 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr b(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("override-client-update", b);
 }
-#line 3277 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3305 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 599:
-#line 2074 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2102 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.REPLACE_CLIENT_NAME);
 }
-#line 3285 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3313 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 600:
-#line 2076 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2104 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("replace-client-name", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3294 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3322 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 601:
-#line 2082 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2110 "dhcp6_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("when-present", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3302 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3330 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 602:
-#line 2085 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2113 "dhcp6_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("never", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3310 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3338 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 603:
-#line 2088 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2116 "dhcp6_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("always", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3318 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3346 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 604:
-#line 2091 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2119 "dhcp6_parser.yy" // lalr1.cc:859
     {
       yylhs.value.as< ElementPtr > () = ElementPtr(new StringElement("when-not-present", ctx.loc2pos(yystack_[0].location)));
       }
-#line 3326 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3354 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 605:
-#line 2094 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2122 "dhcp6_parser.yy" // lalr1.cc:859
     {
       error(yystack_[0].location, "boolean values for the replace-client-name are "
                 "no longer supported");
       }
-#line 3335 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3363 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 606:
-#line 2100 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2128 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3343 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3371 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 607:
-#line 2102 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2130 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("generated-prefix", s);
     ctx.leave();
 }
-#line 3353 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3381 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 608:
-#line 2108 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2136 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3361 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3389 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 609:
-#line 2110 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2138 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("hostname-char-set", s);
     ctx.leave();
 }
-#line 3371 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3399 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 610:
-#line 2116 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2144 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3379 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3407 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 611:
-#line 2118 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2146 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr s(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("hostname-char-replacement", s);
     ctx.leave();
 }
-#line 3389 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3417 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 612:
-#line 2126 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2154 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3397 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3425 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 613:
-#line 2128 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2156 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("Dhcp4", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3406 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3434 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 614:
-#line 2133 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2161 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3414 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3442 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 615:
-#line 2135 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2163 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("DhcpDdns", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3423 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3451 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 616:
-#line 2140 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2168 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3431 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3459 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 617:
-#line 2142 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2170 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.back()->set("Control-agent", yystack_[0].value.as< ElementPtr > ());
     ctx.leave();
 }
-#line 3440 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3468 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 618:
-#line 2149 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2177 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
 }
-#line 3450 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3478 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 619:
-#line 2153 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2181 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3458 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3486 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 620:
-#line 2158 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2186 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr i(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("config-control", i);
     ctx.stack_.push_back(i);
     ctx.enter(ctx.CONFIG_CONTROL);
 }
-#line 3469 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3497 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 621:
-#line 2163 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2191 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // No config control params are required
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3479 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3507 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 622:
-#line 2169 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2197 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // Parse the config-control map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3489 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3517 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 623:
-#line 2173 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2201 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // No config_control params are required
     // parsing completed
 }
-#line 3498 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3526 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 628:
-#line 2188 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2216 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("config-databases", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.CONFIG_DATABASE);
 }
-#line 3509 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3537 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 629:
-#line 2193 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2221 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3518 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3546 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 630:
-#line 2203 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2231 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("Logging", m);
     ctx.stack_.push_back(m);
     ctx.enter(ctx.LOGGING);
 }
-#line 3529 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3557 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 631:
-#line 2208 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2236 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3538 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3566 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 632:
-#line 2213 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2241 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // Parse the Logging map
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.push_back(m);
 }
-#line 3548 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3576 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 633:
-#line 2217 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2245 "dhcp6_parser.yy" // lalr1.cc:859
     {
     // parsing completed
 }
-#line 3556 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3584 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 637:
-#line 2233 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2261 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("loggers", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.LOGGERS);
 }
-#line 3567 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3595 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 638:
-#line 2238 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2266 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3576 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3604 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 641:
-#line 2250 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2278 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(l);
     ctx.stack_.push_back(l);
 }
-#line 3586 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3614 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 642:
-#line 2254 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2282 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3594 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3622 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 652:
-#line 2271 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2299 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr dl(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("debuglevel", dl);
 }
-#line 3603 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3631 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 653:
-#line 2276 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2304 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3611 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3639 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 654:
-#line 2278 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2306 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr sev(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("severity", sev);
     ctx.leave();
 }
-#line 3621 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3649 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 655:
-#line 2284 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2312 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr l(new ListElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("output_options", l);
     ctx.stack_.push_back(l);
     ctx.enter(ctx.OUTPUT_OPTIONS);
 }
-#line 3632 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3660 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 656:
-#line 2289 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2317 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
     ctx.leave();
 }
-#line 3641 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3669 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 659:
-#line 2298 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2326 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr m(new MapElement(ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->add(m);
     ctx.stack_.push_back(m);
 }
-#line 3651 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3679 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 660:
-#line 2302 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2330 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.stack_.pop_back();
 }
-#line 3659 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3687 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 667:
-#line 2316 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2344 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ctx.enter(ctx.NO_KEYWORD);
 }
-#line 3667 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3695 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 668:
-#line 2318 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2346 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr sev(new StringElement(yystack_[0].value.as< std::string > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("output", sev);
     ctx.leave();
 }
-#line 3677 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3705 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 669:
-#line 2324 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2352 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr flush(new BoolElement(yystack_[0].value.as< bool > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("flush", flush);
 }
-#line 3686 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3714 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 670:
-#line 2329 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2357 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr maxsize(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("maxsize", maxsize);
 }
-#line 3695 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3723 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
   case 671:
-#line 2334 "dhcp6_parser.yy" // lalr1.cc:859
+#line 2362 "dhcp6_parser.yy" // lalr1.cc:859
     {
     ElementPtr maxver(new IntElement(yystack_[0].value.as< int64_t > (), ctx.loc2pos(yystack_[0].location)));
     ctx.stack_.back()->set("maxver", maxver);
 }
-#line 3704 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3732 "dhcp6_parser.cc" // lalr1.cc:859
     break;
 
 
-#line 3708 "dhcp6_parser.cc" // lalr1.cc:859
+#line 3736 "dhcp6_parser.cc" // lalr1.cc:859
             default:
               break;
             }
@@ -4970,19 +4998,19 @@ namespace isc { namespace dhcp {
     1836,  1837,  1838,  1839,  1840,  1841,  1842,  1843,  1844,  1847,
     1847,  1854,  1855,  1856,  1859,  1864,  1864,  1872,  1877,  1884,
     1891,  1891,  1901,  1902,  1905,  1906,  1907,  1908,  1909,  1912,
-    1912,  1920,  1920,  1930,  1930,  1948,  1948,  1960,  1960,  1970,
-    1971,  1974,  1975,  1976,  1977,  1978,  1979,  1980,  1981,  1982,
-    1983,  1984,  1985,  1986,  1987,  1988,  1989,  1990,  1991,  1992,
-    1995,  2000,  2000,  2008,  2008,  2016,  2021,  2021,  2029,  2034,
-    2039,  2039,  2047,  2048,  2051,  2051,  2059,  2064,  2069,  2074,
-    2074,  2082,  2085,  2088,  2091,  2094,  2100,  2100,  2108,  2108,
-    2116,  2116,  2126,  2126,  2133,  2133,  2140,  2140,  2149,  2149,
-    2158,  2158,  2169,  2169,  2179,  2180,  2184,  2185,  2188,  2188,
-    2203,  2203,  2213,  2213,  2224,  2225,  2229,  2233,  2233,  2245,
-    2246,  2250,  2250,  2258,  2259,  2262,  2263,  2264,  2265,  2266,
-    2267,  2268,  2271,  2276,  2276,  2284,  2284,  2294,  2295,  2298,
-    2298,  2306,  2307,  2310,  2311,  2312,  2313,  2316,  2316,  2324,
-    2329,  2334
+    1912,  1920,  1920,  1930,  1930,  1976,  1976,  1988,  1988,  1998,
+    1999,  2002,  2003,  2004,  2005,  2006,  2007,  2008,  2009,  2010,
+    2011,  2012,  2013,  2014,  2015,  2016,  2017,  2018,  2019,  2020,
+    2023,  2028,  2028,  2036,  2036,  2044,  2049,  2049,  2057,  2062,
+    2067,  2067,  2075,  2076,  2079,  2079,  2087,  2092,  2097,  2102,
+    2102,  2110,  2113,  2116,  2119,  2122,  2128,  2128,  2136,  2136,
+    2144,  2144,  2154,  2154,  2161,  2161,  2168,  2168,  2177,  2177,
+    2186,  2186,  2197,  2197,  2207,  2208,  2212,  2213,  2216,  2216,
+    2231,  2231,  2241,  2241,  2252,  2253,  2257,  2261,  2261,  2273,
+    2274,  2278,  2278,  2286,  2287,  2290,  2291,  2292,  2293,  2294,
+    2295,  2296,  2299,  2304,  2304,  2312,  2312,  2322,  2323,  2326,
+    2326,  2334,  2335,  2338,  2339,  2340,  2341,  2344,  2344,  2352,
+    2357,  2362
   };
 
   // Print the state stack on the debug stream.
@@ -5017,8 +5045,8 @@ namespace isc { namespace dhcp {
 
 #line 14 "dhcp6_parser.yy" // lalr1.cc:1167
 } } // isc::dhcp
-#line 5021 "dhcp6_parser.cc" // lalr1.cc:1167
-#line 2339 "dhcp6_parser.yy" // lalr1.cc:1168
+#line 5049 "dhcp6_parser.cc" // lalr1.cc:1167
+#line 2367 "dhcp6_parser.yy" // lalr1.cc:1168
 
 
 void
index 2328636e6fbd4df81a3e4af7ebe81aa1ec91e50b..6209de3069fcae6bfb5522f39a60e28ff8cd2fa1 100644 (file)
@@ -1933,13 +1933,41 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL {
     ElementPtr qc = $4;
     ctx.stack_.back()->set("dhcp-queue-control", qc);
 
-    if (!qc->contains("queue-type")) {
+    // Doing this manually, because dhcp-queue-control
+    // content is otherwise arbitrary
+    if (!qc->contains("enable-queue")) {
         std::stringstream msg;
-        msg << "'queue-type' is required: ";
+        msg << "'enable-queue' is required: ";
         msg  << qc->getPosition().str() << ")";
         error(@1, msg.str());
     }
 
+     ConstElementPtr enable_queue = qc->get("enable-queue");
+     if (enable_queue->getType() != Element::boolean) {
+        std::stringstream msg;
+        msg << "'enable-queue' must be boolean: ";
+        msg  << qc->getPosition().str() << ")";
+        error(@1, msg.str());
+     }
+
+    if (enable_queue->boolValue()) {
+        if (!qc->contains("queue-type")) {
+            std::stringstream msg;
+            msg << "'queue-type' is required, when 'enable-queue' is true: ";
+            msg  << qc->getPosition().str() << ")";
+            error(@1, msg.str());
+        }
+
+        ConstElementPtr queue_type = qc->get("queue-type");
+        if (queue_type->getType() != Element::string) {
+            std::stringstream msg;
+            msg << "'queue-type' must be a string: ";
+            msg  << qc->getPosition().str() << ")";
+            error(@1, msg.str());
+        }
+     }
+
+
     ctx.leave();
 };
 
index 3ff82c89bb82a3957f30a8fdb00936e8c46e951b..6def10c74af7546fa3dc4ba8a3f3a3635fee66b2 100644 (file)
@@ -484,7 +484,7 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
             }
 
             if (config_pair.first == "dhcp-queue-control") {
-                DHCPQueueControlParser parser(AF_INET);
+                DHCPQueueControlParser parser;
                 srv_config->setDHCPQueueControl(parser.parse(config_pair.second));
                 continue;
             }
index 027afcd498896ea8247669ffcf7a2ab2a905d883..757c46bf1a55fb6f6efe0da426945ba9a981bed3 100644 (file)
@@ -6938,20 +6938,33 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControl) {
         ""
         },
         {
-        "valid entry",
+        "queue disabled",
         "{ \n"
-        "   \"queue-type\": \"some-type\", \n"
-        "   \"capacity\": 75 \n"
+        "   \"enable-queue\": false \n"
+        "} \n"
+        },
+        {
+        "queue disabled, arbitrary content allowed",
+        "{ \n"
+        "   \"enable-queue\": false, \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
         "} \n"
         },
         {
-        "valid arbitrary content",
+        "queue enabled, with queue-type",
         "{ \n"
-        "       \"queue-type\": \"some-type\", \n"
-        "       \"capacity\": 90, \n"
-        "       \"user-context\": { \"comment\": \"some text\" },\n"
-        "       \"random-bool\" : false, \n"
-        "       \"random-int\" : 1236 \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\" \n"
+        "} \n"
+        },
+        {
+        "queue enabled with queue-type and arbitrary content",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\", \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
         "} \n"
         }
     };
@@ -6961,9 +6974,7 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControl) {
     control = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
     ASSERT_FALSE(control);
 
-    // Iterate over the incorrect scenarios and verify they
-    // fail as expected. Note, we use parseDHCP6() directly
-    // as all of the errors above are enforced by the grammar.
+    // Iterate over the valid scenarios and verify they succeed.
     data::ConstElementPtr exp_elems;
     for (auto scenario : scenarios) {
         SCOPED_TRACE(scenario.description_);
@@ -7008,24 +7019,43 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) {
     struct Scenario {
         std::string description_;
         std::string json_;
+        std::string exp_error_;
     };
 
     std::vector<Scenario> scenarios = {
         {
-            "not a map",
-            "{ " + genIfaceConfig() + ", \n" +
-            "   \"subnet6\": [  ],  \n"
-            "   \"dhcp-queue-control\": 75 \n"
-            "} \n"
+        "not a map",
+        "75 \n",
+        "<string>:2.24-25: syntax error, unexpected integer, expecting {"
+        },
+        {
+        "enable-queue missing",
+        "{ \n"
+        "   \"enable-type\": \"some-type\" \n"
+        "} \n",
+        "<string>:2.2-21: 'enable-queue' is required: <string>:2:24)"
+        },
+        {
+        "enable-queue not boolean",
+        "{ \n"
+        "   \"enable-queue\": \"always\" \n"
+        "} \n",
+        "<string>:2.2-21: 'enable-queue' must be boolean: <string>:2:24)"
         },
         {
-            "queue type missing",
-            "{ " + genIfaceConfig() + ", \n" +
-            "   \"subnet6\": [  ],  \n"
-            "   \"dhcp-queue-control\": { \n"
-            "       \"capacity\": 100 \n"
-            "   } \n"
-            "} \n"
+        "queue enabled, type missing",
+        "{ \n"
+        "   \"enable-queue\": true \n"
+        "} \n",
+        "<string>:2.2-21: 'queue-type' is required, when 'enable-queue' is true: <string>:2:24)"
+        },
+        {
+        "queue enabled, type not a string",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": 7777 \n"
+        "} \n",
+        "<string>:2.2-21: 'queue-type' must be a string: <string>:2:24)"
         }
     };
 
@@ -7035,7 +7065,21 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) {
     for (auto scenario : scenarios) {
         SCOPED_TRACE(scenario.description_);
         {
-            EXPECT_THROW(parseDHCP6(scenario.json_), Dhcp6ParseError);
+            // Construct the config JSON
+            std::stringstream os;
+            os << "{ " + genIfaceConfig();
+            os << ",\n \"dhcp-queue-control\": "  <<  scenario.json_;
+            os << "} \n";
+
+            std::string error_msg = "";
+            try {
+                ASSERT_TRUE(parseDHCP6(os.str(), false)) << "parser returned empty element";
+            } catch(const std::exception& ex) {
+                error_msg = ex.what();
+            }
+
+            ASSERT_FALSE(error_msg.empty()) << "parseDHCP6 should have thrown";
+            EXPECT_EQ(scenario.exp_error_, error_msg);
         }
     }
 }
index 8792b216e65b2b97efd3ae1c60a10c010995ca11..8c6ace93fc6299f14ed2997e716aabad4f601990 100644 (file)
@@ -93,6 +93,7 @@ Iface::closeSockets(const uint16_t family) {
                   << " specified when requested to close all sockets"
                   << " which belong to this family");
     }
+
     // Search for the socket of the specific type.
     SocketCollection::iterator sock = sockets_.begin();
     while (sock != sockets_.end()) {
@@ -282,6 +283,9 @@ Iface::countActive4() const {
 }
 
 void IfaceMgr::closeSockets() {
+    // Stops the receiver thread if there is one.
+    stopDHCPReceiver();
+
     BOOST_FOREACH(IfacePtr iface, ifaces_) {
         iface->closeSockets();
     }
@@ -293,11 +297,17 @@ void IfaceMgr::stopDHCPReceiver() {
         receiver_thread_->wait();
         receiver_thread_.reset();
         error_watch_.clearReady();
+
     }
     receiver_error_ = "no error";
 
-    getPacketQueue4()->clear();
-    getPacketQueue4()->clear();
+    if (getPacketQueue4()) {
+        getPacketQueue4()->clear();
+    }
+
+    if (getPacketQueue6()) {
+        getPacketQueue6()->clear();
+    }
 }
 
 IfaceMgr::~IfaceMgr() {
@@ -584,6 +594,12 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
 
         }
     }
+
+    if (count > 0) {
+        // starts the receiver thread (if queueing is enabled);
+        startDHCPReceiver(AF_INET);
+    }
+
     return (count > 0);
 }
 
@@ -662,6 +678,11 @@ IfaceMgr::openSockets6(const uint16_t port,
 
         }
     }
+
+    if (count > 0) {
+        // starts the receiver thread (if queueing is enabled);
+        startDHCPReceiver(AF_INET6);
+    }
     return (count > 0);
 }
 
@@ -674,14 +695,14 @@ IfaceMgr::startDHCPReceiver(const uint16_t family) {
     switch (family) {
     case AF_INET:
         if(!getPacketQueue4()) {
-            isc_throw(Unexpected, "startDHCPRecever - no packet queue?");
+            return;
         }
 
         receiver_thread_.reset(new Thread(boost::bind(&IfaceMgr::receiveDHCP4Packets, this)));
         break;
     case AF_INET6:
         if(!getPacketQueue6()) {
-            isc_throw(Unexpected, "startDHCPRecever - no packet queue?");
+            return;
         }
 
         receiver_thread_.reset(new Thread(boost::bind(&IfaceMgr::receiveDHCP6Packets, this)));
@@ -942,8 +963,15 @@ IfaceMgr::send(const Pkt4Ptr& pkt) {
     return (packet_filter_->send(*iface, getSocket(*pkt).sockfd_, pkt));
 }
 
-
 Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
+    if (receiver_thread_) {
+        return (receive4Indirect(timeout_sec, timeout_usec));
+    }
+
+    return (receive4Direct(timeout_sec, timeout_usec));
+}
+
+Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
     // Sanity check for microsecond timeout.
     if (timeout_usec >= 1000000) {
         isc_throw(BadValue, "fractional timeout must be shorter than"
@@ -1051,7 +1079,233 @@ Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     return (pkt);
 }
 
-Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
+Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
+    // Sanity check for microsecond timeout.
+    if (timeout_usec >= 1000000) {
+        isc_throw(BadValue, "fractional timeout must be shorter than"
+                  " one million microseconds");
+    }
+    boost::scoped_ptr<SocketInfo> candidate;
+    IfacePtr iface;
+    fd_set sockets;
+    int maxfd = 0;
+
+    FD_ZERO(&sockets);
+
+    /// @todo: marginal performance optimization. We could create the set once
+    /// and then use its copy for select(). Please note that select() modifies
+    /// provided set to indicated which sockets have something to read.
+    BOOST_FOREACH(iface, ifaces_) {
+        BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+
+            // Only deal with IPv4 addresses.
+            if (s.addr_.isV4()) {
+
+                // Add this socket to listening set
+                FD_SET(s.sockfd_, &sockets);
+                if (maxfd < s.sockfd_) {
+                    maxfd = s.sockfd_;
+                }
+            }
+        }
+    }
+
+    // if there are any callbacks for external sockets registered...
+    if (!callbacks_.empty()) {
+        BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+            FD_SET(s.socket_, &sockets);
+            if (maxfd < s.socket_) {
+                maxfd = s.socket_;
+            }
+        }
+    }
+
+    struct timeval select_timeout;
+    select_timeout.tv_sec = timeout_sec;
+    select_timeout.tv_usec = timeout_usec;
+
+    // zero out the errno to be safe
+    errno = 0;
+
+    int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
+
+    if (result == 0) {
+        // nothing received and timeout has been reached
+        return (Pkt4Ptr()); // NULL
+
+    } else if (result < 0) {
+        // In most cases we would like to know whether select() returned
+        // an error because of a signal being received  or for some other
+        // reason. This is because DHCP servers use signals to trigger
+        // certain actions, like reconfiguration or graceful shutdown.
+        // By catching a dedicated exception the caller will know if the
+        // error returned by the function is due to the reception of the
+        // signal or for some other reason.
+        if (errno == EINTR) {
+            isc_throw(SignalInterruptOnSelect, strerror(errno));
+        } else {
+            isc_throw(SocketReadError, strerror(errno));
+        }
+    }
+
+    // Let's find out which socket has the data
+    BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+        if (!FD_ISSET(s.socket_, &sockets)) {
+            continue;
+        }
+
+        // something received over external socket
+
+        // Calling the external socket's callback provides its service
+        // layer access without integrating any specific features
+        // in IfaceMgr
+        if (s.callback_) {
+            s.callback_();
+        }
+
+        return (Pkt4Ptr());
+    }
+
+    // Let's find out which interface/socket has the data
+    BOOST_FOREACH(iface, ifaces_) {
+        BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+            if (FD_ISSET(s.sockfd_, &sockets)) {
+                candidate.reset(new SocketInfo(s));
+                break;
+            }
+        }
+        if (candidate) {
+            break;
+        }
+    }
+
+    if (!candidate) {
+        isc_throw(SocketReadError, "received data over unknown socket");
+    }
+
+    // Now we have a socket, let's get some data from it!
+    // Assuming that packet filter is not NULL, because its modifier checks it.
+    return (packet_filter_->receive(*iface, *candidate));
+}
+
+Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
+    if (receiver_thread_) {
+        return (receive6Indirect(timeout_sec, timeout_usec));
+    }
+
+    return (receive6Direct(timeout_sec, timeout_usec));
+}
+
+Pkt6Ptr IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
+    // Sanity check for microsecond timeout.
+    if (timeout_usec >= 1000000) {
+        isc_throw(BadValue, "fractional timeout must be shorter than"
+                  " one million microseconds");
+    }
+
+    boost::scoped_ptr<SocketInfo> candidate;
+    fd_set sockets;
+    int maxfd = 0;
+
+    FD_ZERO(&sockets);
+
+    /// @todo: marginal performance optimization. We could create the set once
+    /// and then use its copy for select(). Please note that select() modifies
+    /// provided set to indicated which sockets have something to read.
+    BOOST_FOREACH(IfacePtr iface, ifaces_) {
+
+        BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+            // Only deal with IPv6 addresses.
+            if (s.addr_.isV6()) {
+
+                // Add this socket to listening set
+                FD_SET(s.sockfd_, &sockets);
+                if (maxfd < s.sockfd_) {
+                    maxfd = s.sockfd_;
+                }
+            }
+        }
+    }
+
+    // if there are any callbacks for external sockets registered...
+    if (!callbacks_.empty()) {
+        BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+            // Add it to the set as well
+            FD_SET(s.socket_, &sockets);
+            if (maxfd < s.socket_) {
+                maxfd = s.socket_;
+            }
+        }
+    }
+
+    struct timeval select_timeout;
+    select_timeout.tv_sec = timeout_sec;
+    select_timeout.tv_usec = timeout_usec;
+
+    // zero out the errno to be safe
+    errno = 0;
+
+    int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
+
+    if (result == 0) {
+        // nothing received and timeout has been reached
+        return (Pkt6Ptr()); // NULL
+
+    } else if (result < 0) {
+        // In most cases we would like to know whether select() returned
+        // an error because of a signal being received  or for some other
+        // reason. This is because DHCP servers use signals to trigger
+        // certain actions, like reconfiguration or graceful shutdown.
+        // By catching a dedicated exception the caller will know if the
+        // error returned by the function is due to the reception of the
+        // signal or for some other reason.
+        if (errno == EINTR) {
+            isc_throw(SignalInterruptOnSelect, strerror(errno));
+        } else {
+            isc_throw(SocketReadError, strerror(errno));
+        }
+    }
+
+    // Let's find out which socket has the data
+    BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+        if (!FD_ISSET(s.socket_, &sockets)) {
+            continue;
+        }
+
+        // something received over external socket
+
+        // Calling the external socket's callback provides its service
+        // layer access without integrating any specific features
+        // in IfaceMgr
+        if (s.callback_) {
+            s.callback_();
+        }
+
+        return (Pkt6Ptr());
+    }
+
+    // Let's find out which interface/socket has the data
+    BOOST_FOREACH(IfacePtr iface, ifaces_) {
+        BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+            if (FD_ISSET(s.sockfd_, &sockets)) {
+                candidate.reset(new SocketInfo(s));
+                break;
+            }
+        }
+        if (candidate) {
+            break;
+        }
+    }
+
+    if (!candidate) {
+        isc_throw(SocketReadError, "received data over unknown socket");
+    }
+    // Assuming that packet filter is not NULL, because its modifier checks it.
+    return (packet_filter6_->receive(*candidate));
+}
+
+
+Pkt6Ptr IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
     // Sanity check for microsecond timeout.
     if (timeout_usec >= 1000000) {
         isc_throw(BadValue, "fractional timeout must be shorter than"
@@ -1485,5 +1739,42 @@ IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
     return (*candidate);
 }
 
+bool
+IfaceMgr::configureDHCPPacketQueue(uint16_t family, data::ConstElementPtr queue_control) {
+    if (receiver_thread_) {
+        isc_throw(InvalidOperation, "Cannot reconfigure queueing"
+                                    " while receiver thread is running");
+    }
+
+    bool enable_queue = false;
+    if (queue_control) {
+        try {
+            enable_queue = data::SimpleParser::getBoolean(queue_control, "enable-queue");
+        } catch (...) {
+            // @todo - for now swallow not found errors.
+            // if not present we assume default
+        }
+    }
+
+    if (enable_queue) {
+        // Try to create the queue as configured.
+        if (family == AF_INET) {
+            PacketQueueMgr4::instance().createPacketQueue(queue_control);
+        } else {
+            PacketQueueMgr6::instance().createPacketQueue(queue_control);
+        }
+    } else {
+        // Destroy the current queue (if one), this inherently disables threading.
+        if (family == AF_INET) {
+            PacketQueueMgr4::instance().destroyPacketQueue();
+        } else {
+            PacketQueueMgr6::instance().destroyPacketQueue();
+        }
+    }
+
+    return(enable_queue);
+}
+
+
 } // end of namespace isc::dhcp
 } // end of namespace isc
index 979e2667a7da9d7e401f02c27f2cd526423f90ad..37c4d1ffe459da65f6b8524d232d7ed2d0ff5027 100644 (file)
@@ -699,6 +699,9 @@ public:
     /// @return Pkt6 object representing received packet (or NULL)
     Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
 
+    Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
+    Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
+
     /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
     ///
     /// Attempts to receive a single DHCPv4 message over any of the open
@@ -721,6 +724,9 @@ public:
     /// @return Pkt4 object representing received packet (or NULL)
     Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
 
+    Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
+    Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
+
     /// Opens UDP/IP socket and binds it to address, interface and port.
     ///
     /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
@@ -808,6 +814,9 @@ public:
     /// but it is not running, it is down, or is a loopback interface when
     /// loopback is not allowed, an error is reported.
     ///
+    /// If sockets were successfully opened, it calls @ startDHCPReceiver to
+    /// start the receiver thread (if packet queueing is enabled).
+    ///
     /// On the systems with multiple interfaces, it is often desired that the
     /// failure to open a socket on a particular interface doesn't cause a
     /// fatal error and sockets should be opened on remaining interfaces.
@@ -857,6 +866,9 @@ public:
     /// represented by a class derived from @c isc::dhcp::PktFilter abstract
     /// class.
     ///
+    /// If sockets were successfully opened, it calls @ startDHCPReceiver to
+    /// start the receiver thread (if packet queueing is enabled).
+    ///
     /// It is possible to specify whether sockets should be broadcast capable.
     /// In most of the cases, the sockets should support broadcast traffic, e.g.
     /// DHCPv4 server and relay need to listen to broadcast messages sent by
@@ -916,6 +928,10 @@ public:
                       IfaceMgrErrorMsgCallback error_handler = 0);
 
     /// @brief Closes all open sockets.
+    ///
+    /// It calls @c stopDHCPReceiver to stop the receiver thread and then
+    /// it closes all open interface sockets.
+    ///
     /// Is used in destructor, but also from Dhcpv4Srv and Dhcpv6Srv classes.
     void closeSockets();
 
@@ -1047,7 +1063,8 @@ public:
     /// @brief Starts DHCP packet receiver.
     ///
     /// Starts the DHCP packet receiver thread for the given.
-    /// protocol, AF_NET or AF_INET6
+    /// protocol, AF_NET or AF_INET6, if the packet queue
+    /// exists, otherwise it simply returns.
     ///
     /// @param family indicates which receiver to start,
     /// (AF_INET or AF_INET6)
@@ -1057,9 +1074,27 @@ public:
 
     /// @brief Stops the DHCP packet receiver.
     ///
-    /// Stops the receiver and deletes the dedicated thread.
+    /// If the thread exists, it is stopped, deleted, and
+    /// the packet queue is flushed.
     void stopDHCPReceiver();
 
+    /// @brief Configures DHCP packet queue
+    ///
+    /// If the given configuration enables packet queueing, then the
+    /// appropriate queue is created. Otherwise, the existing queue is
+    /// destroyed. If the receiver thread is running when this function
+    /// is invoked, it will throw.
+    ///
+    /// @param family indicates which receiver to start,
+    /// (AF_INET or AF_INET6)
+    /// @parm queue_control configuration containing "dhcp-queue-control"
+    /// content
+    /// @return true if packet queueuing has been enabled, false otherwise
+    /// @throw InvalidOperation if the receiver thread is currently running.
+    bool configureDHCPPacketQueue(const uint16_t family,
+                                  data::ConstElementPtr queue_control);
+
+
     // don't use private, we need derived classes in tests
 protected:
 
index e34bf261e51a24ec328c7d505ed8bae59e433e27..5b1d4da7796edccc865b44d6dbb854ac9c0eaa7e 100644 (file)
@@ -158,6 +158,12 @@ public:
         return (packet_queue_);
     }
 
+    /// @brief Destroys the current packet queue.
+    /// Any queued packets will be discarded.
+    void destroyPacketQueue() {
+        packet_queue_.reset();
+    }
+
 protected:
     /// @brief A map holding registered backend factory functions.
     std::map<std::string, Factory> factories_;
index 079c067de16a0885daa8726f005d4bd24a2a78e2..82f7740fc8e1fccbb880c5cb8c5780ce97ea950c 100644 (file)
@@ -30,11 +30,6 @@ PacketQueueMgr4::PacketQueueMgr4() {
             PacketQueue4Ptr queue(new PacketQueueRing4("kea-ring4", capacity));
             return (queue);
         });
-
-    data::ElementPtr parameters = data::Element::createMap();
-    parameters->set("queue-type", data::Element::create("kea-ring4"));
-    parameters->set("capacity", data::Element::create(static_cast<long int>(500)));
-    createPacketQueue(parameters);
 }
 
 boost::scoped_ptr<PacketQueueMgr4>&
index dc1a26bb77ec2270b5d0f1e2fcb25d2fac2a4b28..a770f51d0c69afa8172d6bdcf1e0822430c7d502 100644 (file)
@@ -55,8 +55,7 @@ public:
 private:
     /// @brief Private constructor.
     ///
-    /// It registers a default factory for DHCPv4 queues and creates
-    /// an default DHCPv4 packet queue.
+    /// It registers a default factory for DHCPv4 queues. 
     PacketQueueMgr4();
 
     /// @brief Returns a pointer to the currently instance of the
index b6c8ad9212f96d429242d4f0c837261dc795a737..705daaa66cb3ef08d20297e6d1060194973bda7e 100644 (file)
@@ -30,11 +30,6 @@ PacketQueueMgr6::PacketQueueMgr6() {
             PacketQueue6Ptr queue(new PacketQueueRing6("kea-ring6", capacity));
             return (queue);
         });
-
-    data::ElementPtr parameters = data::Element::createMap();
-    parameters->set("queue-type", data::Element::create("kea-ring6"));
-    parameters->set("capacity", data::Element::create(static_cast<long int>(500)));
-    createPacketQueue(parameters);
 }
 
 boost::scoped_ptr<PacketQueueMgr6>&
index fb9d4e505748dc93696ac1cbe8c6a7fa03f09770..a4d89301eeeff288b2a485f650699bcad6e7074c 100644 (file)
@@ -56,8 +56,7 @@ public:
 private:
     /// @brief Private constructor.
     ///
-    /// It registers a default factory for DHCPv6 queues and creates
-    /// an default DHCPv6 packet queue.
+    /// It registers a default factory for DHCPv6 queues.
     PacketQueueMgr6();
 
     /// @brief Returns a pointer to the currently used instance of the
index 7975efbc1b8881bca16bbe2f38d47d0421f454d8..fb4114f58666499fba9063d6e42f1857cc64cba9 100644 (file)
@@ -645,12 +645,14 @@ TEST_F(IfaceMgrTest, clearIfaces) {
 TEST_F(IfaceMgrTest, packetQueue4) {
     NakedIfaceMgr ifacemgr;
 
-    // Get the default queue.
-    PacketQueue4Ptr q4 = ifacemgr.getPacketQueue4();
-    ASSERT_TRUE(q4);
+    // Should not have a queue at start up.
+    ASSERT_FALSE(ifacemgr.getPacketQueue4());
 
-    // Verify that the queue is what we expect.
-    checkInfo(q4, "{ \"capacity\": 500, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
+    // Verify that we can create a queue with default factory.
+    data::ConstElementPtr config = makeQueueConfig("kea-ring4", 2000);
+    ASSERT_NO_THROW(PacketQueueMgr4::instance().createPacketQueue(config));
+    checkInfo(ifacemgr.getPacketQueue4(),
+              "{ \"capacity\": 2000, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
 
     // Verify that fetching the queue via IfaceMgr and PacketQueueMgr
     // returns the same queue.
@@ -661,18 +663,20 @@ TEST_F(IfaceMgrTest, packetQueue4) {
 TEST_F(IfaceMgrTest, packetQueue6) {
     NakedIfaceMgr ifacemgr;
 
-    // Get the default queue.
-    PacketQueue6Ptr q6 = ifacemgr.getPacketQueue6();
+    // Should not have a queue at start up.
+    ASSERT_FALSE(ifacemgr.getPacketQueue6());
 
-    // Verify that we have a default queue and its info is correct.
-    checkInfo(q6, "{ \"capacity\": 500, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
+    // Verify that we can create a queue with default factory.
+    data::ConstElementPtr config = makeQueueConfig("kea-ring6", 2000);
+    ASSERT_NO_THROW(PacketQueueMgr6::instance().createPacketQueue(config));
+    checkInfo(ifacemgr.getPacketQueue6(),
+              "{ \"capacity\": 2000, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
 
     // Verify that fetching the queue via IfaceMgr and PacketQueueMgr
     // returns the same queue.
     ASSERT_EQ(ifacemgr.getPacketQueue6(), PacketQueueMgr6::instance().getPacketQueue());
 }
 
-
 TEST_F(IfaceMgrTest, receiveTimeout6) {
     using namespace boost::posix_time;
     std::cout << "Testing DHCPv6 packet reception timeouts."
@@ -732,7 +736,7 @@ TEST_F(IfaceMgrTest, receiveTimeout6) {
 
 TEST_F(IfaceMgrTest, receiveTimeout4) {
     using namespace boost::posix_time;
-    std::cout << "Testing DHCPv6 packet reception timeouts."
+    std::cout << "Testing DHCPv4 packet reception timeouts."
               << " Test will block for a few seconds when waiting"
               << " for timeout to occur." << std::endl;
 
@@ -745,6 +749,7 @@ TEST_F(IfaceMgrTest, receiveTimeout4) {
     );
     // Socket is open if returned value is non-negative.
     ASSERT_GE(socket1, 0);
+
     // Start receiver.
     ASSERT_NO_THROW(ifacemgr->startDHCPReceiver(AF_INET));
 
@@ -780,8 +785,8 @@ TEST_F(IfaceMgrTest, receiveTimeout4) {
     EXPECT_LE(duration.total_microseconds(), 700000);
 
     // Test with invalid fractional timeout values.
-    EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue);
-    EXPECT_THROW(ifacemgr->receive6(2, 1000005), isc::BadValue);
+    EXPECT_THROW(ifacemgr->receive4(0, 1000000), isc::BadValue);
+    EXPECT_THROW(ifacemgr->receive4(2, 1000005), isc::BadValue);
 
     // Stop receiver.
     EXPECT_NO_THROW(ifacemgr->stopDHCPReceiver());
@@ -1129,7 +1134,9 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
     EXPECT_GE(socket1, 0);
 
+#if 0
     ifacemgr->startDHCPReceiver(AF_INET);
+#endif
 
     boost::shared_ptr<Pkt4> sendPkt(new Pkt4(DHCPDISCOVER, 1234) );
 
@@ -1213,7 +1220,9 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
     EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);
 
+#if 0
     ifacemgr->stopDHCPReceiver();
+#endif
 }
 
 // Verifies that it is possible to set custom packet filter object
index 8e3bbeaec34110ded852aab9b7fcce8b74a4b948..4c0d8bf6070ce9599acb54093b849619f7324d8a 100644 (file)
@@ -96,23 +96,20 @@ public:
 };
 
 // Verifies that DHCPv4 PQM provides a default queue factory
-// and packet queue.
 TEST_F(PacketQueueMgr4Test, defaultQueue) {
+    // Should not be a queue at start-up 
+    ASSERT_FALSE(mgr().getPacketQueue());
 
-    // Verify that we have a default queue and its info is correct.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
-
+    // Verify that we can create a queue with default factory.
     data::ConstElementPtr config = makeQueueConfig("kea-ring4", 2000);
-
-    // Verify that we can replace the default queue with different capacity queue
     ASSERT_NO_THROW(mgr().createPacketQueue(config));
     checkMyInfo("{ \"capacity\": 2000, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
 
     // We should be able to recreate the manager.
     ASSERT_NO_THROW(PacketQueueMgr4::create());
 
-    // And be back to having the default queue.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
+    // Should not be a queue.
+    ASSERT_FALSE(mgr().getPacketQueue());
 }
 
 // Verifies that PQM registry and creation of custome queue implementations.
@@ -125,10 +122,7 @@ TEST_F(PacketQueueMgr4Test, customQueueType) {
     // Register our adjustable-type factory
     ASSERT_TRUE(addCustomQueueType("custom-queue"));
 
-    // We still have our default queue.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
-
-    // Verify that we can replace the default queue with a "custom-queue" queue
+    // Verify that we can create a custom queue.
     ASSERT_NO_THROW(mgr().createPacketQueue(config));
     checkMyInfo("{ \"capacity\": 2000, \"queue-type\": \"custom-queue\", \"size\": 0 }");
 
index ad3ca73db5bf1cd976dd194376b19e615eed1c4f..ef0170922253e24703733f349a9e4a6278db5215 100644 (file)
@@ -84,23 +84,20 @@ public:
 };
 
 // Verifies that DHCPv6 PQM provides a default queue factory
-// and packet queue.
 TEST_F(PacketQueueMgr6Test, defaultQueue) {
+    // Should not be a queue at start-up 
+    ASSERT_FALSE(mgr().getPacketQueue());
 
-    // Verify that we have a default queue and its info is correct.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
-
+    // Verify that we can create a queue with default factory.
     data::ConstElementPtr config = makeQueueConfig("kea-ring6", 2000);
-
-    // Verify that we can replace the default queue with different capacity queue
     ASSERT_NO_THROW(mgr().createPacketQueue(config));
     checkMyInfo("{ \"capacity\": 2000, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
 
     // We should be able to recreate the manager.
     ASSERT_NO_THROW(PacketQueueMgr6::create());
 
-    // And be back to having the default queue.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
+    // Should not be a queue.
+    ASSERT_FALSE(mgr().getPacketQueue());
 }
 
 // Verifies that PQM registry and creation of custome queue implementations.
@@ -113,10 +110,7 @@ TEST_F(PacketQueueMgr6Test, customQueueType) {
     // Register our adjustable-type factory
     ASSERT_TRUE(addCustomQueueType("custom-queue"));
 
-    // We still have our default queue.
-    checkMyInfo("{ \"capacity\": 500, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
-
-    // Verify that we can replace the default queue with a "custom-queue" queue
+    // Verify that we can create a custom queue.
     ASSERT_NO_THROW(mgr().createPacketQueue(config));
     checkMyInfo("{ \"capacity\": 2000, \"queue-type\": \"custom-queue\", \"size\": 0 }");
 
index 31e4a48cc682698e6f620ce54e14864adacfcb18..951d880ee63c5241351e95ab3b5f6b99d61d93a8 100644 (file)
@@ -28,7 +28,6 @@ CfgIface::CfgIface()
 
 void
 CfgIface::closeSockets() const {
-    IfaceMgr::instance().stopDHCPReceiver();
     IfaceMgr::instance().closeSockets();
 }
 
@@ -174,11 +173,7 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
         sopen = IfaceMgr::instance().openSockets6(port, error_callback);
     }
     
-    if (sopen) {
-        // @todo we may consider starting/stopping this when DHCP service is
-        // enable/disabled, rather then when we open sockets.
-        IfaceMgr::instance().startDHCPReceiver(family);
-    } else {
+    if (!sopen) {
         // If no socket were opened, log a warning because the server will
         // not respond to any queries.
         LOG_WARN(dhcpsrv_logger, DHCPSRV_NO_SOCKETS_OPEN);
index b852683ddfe96b107e895dccec73a9ab8b705b44..728c06338af9aa57be880141b94be2d9ec060ce8 100644 (file)
@@ -18,15 +18,6 @@ using namespace isc::data;
 namespace isc {
 namespace dhcp {
 
-DHCPQueueControlParser::DHCPQueueControlParser(const uint16_t family)
-    : family_(family) {
-    // @todo Not sure we need family but just in case.
-    if (family_ != AF_INET && family_ != AF_INET6) {
-        isc_throw(BadValue, "DHCPQueueControlParser - invalid family: "
-                 << family_ << ", must be AF_INET or AF_INET6");
-    }
-}
-
 data::ElementPtr 
 DHCPQueueControlParser::parse(const isc::data::ConstElementPtr& control_elem) {
     // All we really do here is verify that it is a map that
@@ -36,12 +27,17 @@ DHCPQueueControlParser::parse(const isc::data::ConstElementPtr& control_elem) {
         isc_throw(DhcpConfigError, "dhcp-queue-control must be a map");
     }
 
-    ConstElementPtr elem  = control_elem->get("queue-type");
-    if (!elem) {
-        isc_throw(DhcpConfigError, "queue-type is required");
-    } else {
-        if (elem->getType() != Element::string) {
-            isc_throw(DhcpConfigError, "queue-type must be a string");
+    // enable-queue is mandatory.
+    bool enable_queue = getBoolean(control_elem, "enable-queue");
+
+    if (enable_queue) {
+        ConstElementPtr elem  = control_elem->get("queue-type");
+        if (!elem) {
+            isc_throw(DhcpConfigError, "when queue is enabled, queue-type is required");
+        } else {
+            if (elem->getType() != Element::string) {
+                isc_throw(DhcpConfigError, "queue-type must be a string");
+            }
         }
     }
 
index 5d1fbe8ca0f0c709ca2cba7bf4f052041baf9a05..663874903f6cb2e87cb530b8c2691b559d837bc2 100644 (file)
@@ -18,9 +18,16 @@ namespace dhcp {
 ///
 /// This parser parses the "dhcp-queue-control" parameter which holds the
 /// the configurable parameters that tailor DHCP packet queue behavior.
-/// Currently "dhcp-queue-control" is treated as a map of arbitrary values,
-/// with only one required value, "queue-type". This was done to
-/// provide latitude for differing queue implementations.
+/// In order to provide wide latitude to packet queue implementators,
+/// 'dhcp-queue-control' is mostly treated as a map of arbitrary values.
+/// There is only mandatory value, 'enable-queue', which enables/disables
+/// DHCP packet queueing.  If this value is true, then the content must
+/// also include a value for 'queue-type'.  Beyond these values, the
+/// map may contain any combination of valid JSON elements.
+///
+/// Unlike most other parsers, this parser primarily serves to validate
+/// the aforementioned rules, and rather than instantiate an object as
+/// a result, it simply returns a copy original map of elements.
 ///
 /// This parser is used in both DHCPv4 and DHCPv6. Derived parsers
 /// are not needed.
@@ -29,22 +36,19 @@ public:
 
     /// @brief Constructor
     ///
-    /// @param family AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
-    explicit DHCPQueueControlParser(const uint16_t family);
+    DHCPQueueControlParser(){};
 
     /// @brief Parses content of the "dhcp-queue-control".
     ///
-    /// @param values pointer to the content of parsed values
+    /// @param control_elem  MapElement containing the queue control values to
+    /// parse
     ///
-    /// @return A pointer to a newly constructed DHCPQueueControl populated
-    /// with the parsed values
+    /// @return A copy of the of the input MapElement.
     ///
     /// @throw DhcpConfigError if any of the values are invalid.
-    data::ElementPtr parse(const isc::data::ConstElementPtr& values);
+    data::ElementPtr parse(const isc::data::ConstElementPtr& control_elem);
 
 private:
-    /// @brief AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
-    int family_;
 };
 
 }
index 644a4716c1ec44d2e6a0fb614a646d766452b536..ea30468e7a35c2ca96961fe04569fb9a89f89622 100644 (file)
@@ -85,6 +85,7 @@ libdhcpsrv_unittests_SOURCES += csv_lease_file6_unittest.cc
 libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc
 libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc
 libdhcpsrv_unittests_SOURCES += database_connection_unittest.cc
+libdhcpsrv_unittests_SOURCES += dhcp_queue_control_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
 libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
diff --git a/src/lib/dhcpsrv/tests/dhcp_queue_control_parser_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_queue_control_parser_unittest.cc
new file mode 100644 (file)
index 0000000..2aae12b
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/dhcp_queue_control_parser.h>
+#include <testutils/test_to_element.h>
+#include <gtest/gtest.h>
+
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::test;
+
+namespace {
+
+/// @brief Test fixture class for @c DHCPQueueControlParser
+class DHCPQueueControlParserTest : public ::testing::Test {
+protected:
+
+    /// @brief Setup for each test.
+    ///
+    /// Clears the configuration in the @c CfgMgr.
+    virtual void SetUp();
+
+    /// @brief Cleans up after each test.
+    ///
+    /// Clears the configuration in the @c CfgMgr.
+    virtual void TearDown();
+
+};
+
+void
+DHCPQueueControlParserTest::SetUp() {
+    CfgMgr::instance().clear();
+}
+
+void
+DHCPQueueControlParserTest::TearDown() {
+    CfgMgr::instance().clear();
+}
+
+// Verifies that DHCPQueueControlParser handles
+// expected valid dhcp-queue-control contet
+TEST_F(DHCPQueueControlParserTest, validContent) {
+    struct Scenario {
+        std::string description_;
+        std::string json_;
+    };
+
+    std::vector<Scenario> scenarios = {
+        {
+        "queue disabled",
+        "{ \n"
+        "   \"enable-queue\": false \n"
+        "} \n"
+        },
+        {
+        "queue disabled, arbitrary content allowed",
+        "{ \n"
+        "   \"enable-queue\": false, \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
+        "} \n"
+        },
+        {
+        "queue enabled, with queue-type",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\" \n"
+        "} \n"
+        },
+        {
+        "queue enabled with queue-type and arbitrary content",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": \"some-type\", \n"
+        "   \"foo\": \"bogus\", \n"
+        "   \"random-int\" : 1234 \n"
+        "} \n"
+        }
+    };
+
+    // Iterate over the valid scenarios and verify they succeed.
+    ConstElementPtr config_elems;
+    ConstElementPtr queue_control;
+    for (auto scenario : scenarios) {
+        SCOPED_TRACE(scenario.description_);
+        {
+            // Construct the config JSON
+            ASSERT_NO_THROW(config_elems = Element::fromJSON(scenario.json_))
+                            << "invalid JSON, test is broken";
+
+            // Parsing config into a queue control should succeed.
+            DHCPQueueControlParser parser;
+            try {
+                queue_control = parser.parse(config_elems);
+            } catch (const std::exception& ex) {
+                ADD_FAILURE() << "parser threw an exception: " << ex.what();
+            }
+
+            // Verify the resultant queue control.
+            ASSERT_TRUE(queue_control);
+
+            // The parser should have created a duplicate of the
+            // configuration elements.
+            ASSERT_TRUE(queue_control.get() != config_elems.get());
+            EXPECT_TRUE(queue_control->equals(*config_elems));
+        }
+    }
+}
+
+// Verifies that DHCPQueueControlParser correctly catches
+// invalid dhcp-queue-control content
+TEST_F(DHCPQueueControlParserTest, invalidContent) {
+    struct Scenario {
+        std::string description_;
+        std::string json_;
+    };
+
+    std::vector<Scenario> scenarios = {
+        {
+        "enable-queue missing",
+        "{ \n"
+        "   \"enable-type\": \"some-type\" \n"
+        "} \n"
+        },
+        {
+        "enable-queue not boolean",
+        "{ \n"
+        "   \"enable-queue\": \"always\" \n"
+        "} \n"
+        },
+        {
+        "queue enabled, type missing",
+        "{ \n"
+        "   \"enable-queue\": true \n"
+        "} \n"
+        },
+        {
+        "queue enabled, type not a string",
+        "{ \n"
+        "   \"enable-queue\": true, \n"
+        "   \"queue-type\": 7777 \n"
+        "} \n"
+        }
+    };
+
+    // Iterate over the valid scenarios and verify they succeed.
+    ConstElementPtr config_elems;
+    ConstElementPtr queue_control;
+    for (auto scenario : scenarios) {
+        SCOPED_TRACE(scenario.description_);
+        {
+            // Construct the config JSON
+            ASSERT_NO_THROW(config_elems = Element::fromJSON(scenario.json_))
+                            << "invalid JSON, test is broken";
+
+            // Parsing config into a queue control should succeed.
+            DHCPQueueControlParser parser;
+            EXPECT_THROW(parser.parse(config_elems), DhcpConfigError);
+        }
+    }
+}
+
+
+}; // anonymous namespace