From: Francis Dupont Date: Sat, 5 Sep 2020 15:57:39 +0000 (+0200) Subject: [#1102] Checkpoint: dhcpv6 and doc to do X-Git-Tag: Kea-1.9.0~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c13229e2d0feeadef3eacbff5205d7608a166f3d;p=thirdparty%2Fkea.git [#1102] Checkpoint: dhcpv6 and doc to do --- diff --git a/src/bin/agent/agent_parser.yy b/src/bin/agent/agent_parser.yy index a17bd55611..7e014ae8d0 100644 --- a/src/bin/agent/agent_parser.yy +++ b/src/bin/agent/agent_parser.yy @@ -180,11 +180,13 @@ map_content: %empty // empty map // covers all longer lists recursively. not_empty_map: STRING COLON value { // map containing a single entry + ctx.unique($1, ctx.loc2pos(@1)); ctx.stack_.back()->set($1, $3); } | not_empty_map COMMA STRING COLON value { // map consisting of a shorter map followed by // comma and string:value + ctx.unique($3, ctx.loc2pos(@3)); ctx.stack_.back()->set($3, $5); } ; @@ -242,6 +244,7 @@ global_object: CONTROL_AGENT { // top level map (that's already on the stack) and put the new map // on the stack as well, so child elements will be able to add // themselves to it. + ctx.unique("Control-agent", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("Control-agent", m); ctx.stack_.push_back(m); @@ -271,6 +274,7 @@ global_param: http_host ; http_host: HTTP_HOST { + ctx.unique("http-host", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr host(new StringElement($4, ctx.loc2pos(@4))); @@ -279,6 +283,7 @@ http_host: HTTP_HOST { }; http_port: HTTP_PORT COLON INTEGER { + ctx.unique("http-port", ctx.loc2pos(@1)); ElementPtr prf(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("http-port", prf); }; @@ -337,6 +342,7 @@ comment: COMMENT { // --- hooks-libraries --------------------------------------------------------- hooks_libraries: HOOKS_LIBRARIES { + ctx.unique("hooks-libraries", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("hooks-libraries", l); ctx.stack_.push_back(l); @@ -372,6 +378,7 @@ hooks_param: library ; library: LIBRARY { + ctx.unique("library", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr lib(new StringElement($4, ctx.loc2pos(@4))); @@ -380,6 +387,7 @@ library: LIBRARY { }; parameters: PARAMETERS { + ctx.unique("parameters", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON map_value { ctx.stack_.back()->set("parameters", $4); @@ -390,6 +398,7 @@ parameters: PARAMETERS { // --- control-sockets starts here --------------------------------------------- control_sockets: CONTROL_SOCKETS COLON LCURLY_BRACKET { + ctx.unique("control-sockets", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("control-sockets", m); ctx.stack_.push_back(m); @@ -416,6 +425,7 @@ control_socket: dhcp4_server_socket // That's an entry for dhcp4 socket. dhcp4_server_socket: DHCP4_SERVER { + ctx.unique("dhcp4", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("dhcp4", m); ctx.stack_.push_back(m); @@ -427,6 +437,7 @@ dhcp4_server_socket: DHCP4_SERVER { // That's an entry for dhcp6 socket. dhcp6_server_socket: DHCP6_SERVER { + ctx.unique("dhcp6", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("dhcp6", m); ctx.stack_.push_back(m); @@ -438,6 +449,7 @@ dhcp6_server_socket: DHCP6_SERVER { // That's an entry for d2 socket. d2_server_socket: D2_SERVER { + ctx.unique("d2", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("d2", m); ctx.stack_.push_back(m); @@ -462,6 +474,7 @@ control_socket_param: socket_name // This rule defines socket-name parameter. socket_name: SOCKET_NAME { + ctx.unique("socket-name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -471,6 +484,7 @@ socket_name: SOCKET_NAME { // This rule specifies socket type. socket_type: SOCKET_TYPE { + ctx.unique("socket-type", ctx.loc2pos(@1)); ctx.enter(ctx.SOCKET_TYPE); } COLON socket_type_value { ctx.stack_.back()->set("socket-type", $4); @@ -589,6 +603,7 @@ password: PASSWORD { // --- Loggers starts here ----------------------------------------------------- loggers: LOGGERS { + ctx.unique("loggers", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("loggers", l); ctx.stack_.push_back(l); @@ -627,6 +642,7 @@ logger_param: name ; name: NAME { + ctx.unique("name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -635,11 +651,13 @@ name: NAME { }; debuglevel: DEBUGLEVEL COLON INTEGER { + ctx.unique("debuglevel", ctx.loc2pos(@1)); ElementPtr dl(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("debuglevel", dl); }; severity: SEVERITY { + ctx.unique("severity", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -648,6 +666,7 @@ severity: SEVERITY { }; output_options_list: OUTPUT_OPTIONS { + ctx.unique("output_options", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("output_options", l); ctx.stack_.push_back(l); @@ -681,6 +700,7 @@ output_params: output ; output: OUTPUT { + ctx.unique("output", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -689,21 +709,25 @@ output: OUTPUT { }; flush: FLUSH COLON BOOLEAN { + ctx.unique("flush", ctx.loc2pos(@1)); ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("flush", flush); } maxsize: MAXSIZE COLON INTEGER { + ctx.unique("maxsize", ctx.loc2pos(@1)); ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxsize", maxsize); } maxver: MAXVER COLON INTEGER { + ctx.unique("maxver", ctx.loc2pos(@1)); ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxver", maxver); } pattern: PATTERN { + ctx.unique("pattern", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); diff --git a/src/bin/agent/tests/parser_unittests.cc b/src/bin/agent/tests/parser_unittests.cc index 6369a898c6..731c64a7b0 100644 --- a/src/bin/agent/tests/parser_unittests.cc +++ b/src/bin/agent/tests/parser_unittests.cc @@ -619,6 +619,22 @@ TEST(ParserTest, errors) { " \"comment\": \"second\" }}\n", ParserContext::PARSER_AGENT, ":2.23: syntax error, unexpected \",\", expecting }"); + + // duplicate of not string entries + testError("{ \"Control-agent\":{\n" + " \"http-port\": 8000,\n" + " \"http-port\": 8001 }}\n", + ParserContext::PARSER_AGENT, + ":3:2: duplicate http-port entries in " + "Control-agent map (previous at :2:15)"); + + // duplicate of string entries + testError("{ \"Control-agent\":{\n" + " \"http-host\": \"127.0.0.1\",\n" + " \"http-host\": \"::1\" }}\n", + ParserContext::PARSER_AGENT, + ":3:2: duplicate http-host entries in " + "Control-agent map (previous at :2:15)"); } // Check unicode escapes diff --git a/src/bin/d2/d2_parser.yy b/src/bin/d2/d2_parser.yy index 6f25eedd6f..e2bb44b8c1 100644 --- a/src/bin/d2/d2_parser.yy +++ b/src/bin/d2/d2_parser.yy @@ -167,11 +167,13 @@ map_content: %empty // empty map not_empty_map: STRING COLON value { // map containing a single entry + ctx.unique($1, ctx.loc2pos(@1)); ctx.stack_.back()->set($1, $3); } | not_empty_map COMMA STRING COLON value { // map consisting of a shorter map followed by // comma and string:value + ctx.unique($3, ctx.loc2pos(@3)); ctx.stack_.back()->set($3, $5); } ; @@ -225,6 +227,7 @@ syntax_map: LCURLY_BRACKET { // --- dhcp ddns --------------------------------------------- // This represents the single top level entry, e.g. DhcpDdns. global_object: DHCPDDNS { + ctx.unique("DhcpDdns", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("DhcpDdns", m); ctx.stack_.push_back(m); @@ -263,6 +266,7 @@ dhcpddns_param: ip_address ; ip_address: IP_ADDRESS { + ctx.unique("ip-address", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr s(new StringElement($4, ctx.loc2pos(@4))); @@ -271,6 +275,7 @@ ip_address: IP_ADDRESS { }; port: PORT COLON INTEGER { + ctx.unique("port", ctx.loc2pos(@1)); if ($3 <= 0 || $3 >= 65536 ) { error(@3, "port must be greater than zero but less than 65536"); } @@ -279,6 +284,7 @@ port: PORT COLON INTEGER { }; dns_server_timeout: DNS_SERVER_TIMEOUT COLON INTEGER { + ctx.unique("dns-server-timeout", ctx.loc2pos(@1)); if ($3 <= 0) { error(@3, "dns-server-timeout must be greater than zero"); } else { @@ -288,6 +294,7 @@ dns_server_timeout: DNS_SERVER_TIMEOUT COLON INTEGER { }; ncr_protocol: NCR_PROTOCOL { + ctx.unique("ncr-protocol", ctx.loc2pos(@1)); ctx.enter(ctx.NCR_PROTOCOL); } COLON ncr_protocol_value { ctx.stack_.back()->set("ncr-protocol", $4); @@ -300,6 +307,7 @@ ncr_protocol_value: ; ncr_format: NCR_FORMAT { + ctx.unique("ncr-format", ctx.loc2pos(@1)); ctx.enter(ctx.NCR_FORMAT); } COLON JSON { ElementPtr json(new StringElement("JSON", ctx.loc2pos(@4))); @@ -360,6 +368,7 @@ comment: COMMENT { }; forward_ddns : FORWARD_DDNS { + ctx.unique("forward-ddns", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("forward-ddns", m); ctx.stack_.push_back(m); @@ -370,6 +379,7 @@ forward_ddns : FORWARD_DDNS { }; reverse_ddns : REVERSE_DDNS { + ctx.unique("reverse-ddns", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("reverse-ddns", m); ctx.stack_.push_back(m); @@ -394,6 +404,7 @@ ddns_mgr_param: ddns_domains // --- ddns-domains ---------------------------------------- ddns_domains: DDNS_DOMAINS { + ctx.unique("ddns-domains", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("ddns-domains", l); ctx.stack_.push_back(l); @@ -447,6 +458,7 @@ ddns_domain_param: ddns_domain_name // @todo NAME needs to be an FQDN sort of thing ddns_domain_name: NAME { + ctx.unique("name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { if ($4 == "") { @@ -459,6 +471,7 @@ ddns_domain_name: NAME { }; ddns_domain_key_name: KEY_NAME { + ctx.unique("key-name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr elem(new StringElement($4, ctx.loc2pos(@4))); @@ -471,6 +484,7 @@ ddns_domain_key_name: KEY_NAME { // --- dns-servers ---------------------------------------- dns_servers: DNS_SERVERS { + ctx.unique("dns-servers", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("dns-servers", l); ctx.stack_.push_back(l); @@ -519,6 +533,7 @@ dns_server_param: dns_server_hostname ; dns_server_hostname: HOSTNAME { + ctx.unique("hostname", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { if ($4 != "") { @@ -531,6 +546,7 @@ dns_server_hostname: HOSTNAME { }; dns_server_ip_address: IP_ADDRESS { + ctx.unique("ip-address", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr s(new StringElement($4, ctx.loc2pos(@4))); @@ -539,6 +555,7 @@ dns_server_ip_address: IP_ADDRESS { }; dns_server_port: PORT COLON INTEGER { + ctx.unique("port", ctx.loc2pos(@1)); if ($3 <= 0 || $3 >= 65536 ) { error(@3, "port must be greater than zero but less than 65536"); } @@ -553,6 +570,7 @@ dns_server_port: PORT COLON INTEGER { // --- tsig-keys ---------------------------------------- // "tsig-keys" : [ ... ] tsig_keys: TSIG_KEYS { + ctx.unique("tsig-keys", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("tsig-keys", l); ctx.stack_.push_back(l); @@ -608,6 +626,7 @@ tsig_key_param: tsig_key_name ; tsig_key_name: NAME { + ctx.unique("name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { if ($4 == "") { @@ -620,6 +639,7 @@ tsig_key_name: NAME { }; tsig_key_algorithm: ALGORITHM { + ctx.unique("algorithm", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { if ($4 == "") { @@ -631,6 +651,7 @@ tsig_key_algorithm: ALGORITHM { }; tsig_key_digest_bits: DIGEST_BITS COLON INTEGER { + ctx.unique("digest-bits", ctx.loc2pos(@1)); if ($3 < 0 || ($3 > 0 && ($3 % 8 != 0))) { error(@3, "TSIG key digest-bits must either be zero or a positive, multiple of eight"); } @@ -639,6 +660,7 @@ tsig_key_digest_bits: DIGEST_BITS COLON INTEGER { }; tsig_key_secret: SECRET { + ctx.unique("secret", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { if ($4 == "") { @@ -655,6 +677,7 @@ tsig_key_secret: SECRET { // --- control socket ---------------------------------------- control_socket: CONTROL_SOCKET { + ctx.unique("control-socket", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("control-socket", m); ctx.stack_.push_back(m); @@ -676,6 +699,7 @@ control_socket_param: control_socket_type ; control_socket_type: SOCKET_TYPE { + ctx.unique("socket-type", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr stype(new StringElement($4, ctx.loc2pos(@4))); @@ -684,6 +708,7 @@ control_socket_type: SOCKET_TYPE { }; control_socket_name: SOCKET_NAME { + ctx.unique("socket-name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -694,6 +719,7 @@ control_socket_name: SOCKET_NAME { // --- loggers entry ----------------------------------------- loggers: LOGGERS { + ctx.unique("loggers", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("loggers", l); ctx.stack_.push_back(l); @@ -732,6 +758,7 @@ logger_param: name ; name: NAME { + ctx.unique("name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -740,10 +767,13 @@ name: NAME { }; debuglevel: DEBUGLEVEL COLON INTEGER { + ctx.unique("debuglevel", ctx.loc2pos(@1)); ElementPtr dl(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("debuglevel", dl); }; + severity: SEVERITY { + ctx.unique("severity", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -752,6 +782,7 @@ severity: SEVERITY { }; output_options_list: OUTPUT_OPTIONS { + ctx.unique("output_options", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("output_options", l); ctx.stack_.push_back(l); @@ -785,6 +816,7 @@ output_params: output ; output: OUTPUT { + ctx.unique("output", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -793,21 +825,25 @@ output: OUTPUT { }; flush: FLUSH COLON BOOLEAN { + ctx.unique("flush", ctx.loc2pos(@1)); ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("flush", flush); } maxsize: MAXSIZE COLON INTEGER { + ctx.unique("maxsize", ctx.loc2pos(@1)); ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxsize", maxsize); } maxver: MAXVER COLON INTEGER { + ctx.unique("maxver", ctx.loc2pos(@1)); ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxver", maxver); } pattern: PATTERN { + ctx.unique("pattern", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); diff --git a/src/bin/d2/tests/parser_unittest.cc b/src/bin/d2/tests/parser_unittest.cc index 54e0658f7f..dc02f3c6ce 100644 --- a/src/bin/d2/tests/parser_unittest.cc +++ b/src/bin/d2/tests/parser_unittest.cc @@ -563,6 +563,22 @@ TEST(ParserTest, errors) { " \"comment\": \"second\" }}\n", D2ParserContext::PARSER_DHCPDDNS, ":2.23: syntax error, unexpected \",\", expecting }"); + + // duplicate of not string entries + testError("{ \"DhcpDdns\":{\n" + " \"port\": 53001,\n" + " \"port\": 53002 }}\n", + D2ParserContext::PARSER_DHCPDDNS, + ":3:3: duplicate port entries in " + "DhcpDdns map (previous at :2:11)"); + + // duplicate of string entries + testError("{ \"DhcpDdns\":{\n" + " \"ip-address\": \"127.0.0.1\",\n" + " \"ip-address\": \"::1\" }}\n", + D2ParserContext::PARSER_DHCPDDNS, + ":3:3: duplicate ip-address entries in " + "DhcpDdns map (previous at :2:17)"); } // Check unicode escapes diff --git a/src/bin/dhcp4/tests/parser_unittest.cc b/src/bin/dhcp4/tests/parser_unittest.cc index 6374e7db21..aa408e84ea 100644 --- a/src/bin/dhcp4/tests/parser_unittest.cc +++ b/src/bin/dhcp4/tests/parser_unittest.cc @@ -616,6 +616,22 @@ TEST(ParserTest, errors) { " \"comment\": \"second\" }}\n", Parser4Context::PARSER_DHCP4, ":2.23: syntax error, unexpected \",\", expecting }"); + + // duplicate of not string entries + testError("{ \"Dhcp4\":{\n" + " \"subnet4\": [],\n" + " \"subnet4\": [] }}\n", + Parser4Context::PARSER_DHCP4, + ":3:2: duplicate subnet4 entries in " + "Dhcp4 map (previous at :2:2)"); + + // duplicate of string entries + testError("{\n" + " \"server-hostname\": \"nohost\",\n" + " \"server-hostname\": \"nofile\" }\n", + Parser4Context::PARSER_HOST_RESERVATION, + ":3:2: duplicate server-hostname entries in " + "reservations map (previous at :2:21)"); } // Check unicode escapes diff --git a/src/bin/netconf/netconf_parser.yy b/src/bin/netconf/netconf_parser.yy index 002b145a90..c29bd30772 100644 --- a/src/bin/netconf/netconf_parser.yy +++ b/src/bin/netconf/netconf_parser.yy @@ -179,11 +179,13 @@ map_content: %empty // empty map // covers all longer lists recursively. not_empty_map: STRING COLON value { // map containing a single entry + ctx.unique($1, ctx.loc2pos(@1)); ctx.stack_.back()->set($1, $3); } | not_empty_map COMMA STRING COLON value { // map consisting of a shorter map followed by // comma and string:value + ctx.unique($3, ctx.loc2pos(@3)); ctx.stack_.back()->set($3, $5); } ; @@ -277,16 +279,19 @@ global_param: boot_update ; boot_update: BOOT_UPDATE COLON BOOLEAN { + ctx.unique("boot-update", ctx.loc2pos(@1)); ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("boot-update", flag); }; subscribe_changes: SUBSCRIBE_CHANGES COLON BOOLEAN { + ctx.unique("subscribe-changes", ctx.loc2pos(@1)); ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("subscribe-changes", flag); }; validate_changes: VALIDATE_CHANGES COLON BOOLEAN { + ctx.unique("validate-changes", ctx.loc2pos(@1)); ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("validate-changes", flag); }; @@ -345,6 +350,7 @@ comment: COMMENT { // --- hooks-libraries --------------------------------------------------------- hooks_libraries: HOOKS_LIBRARIES { + ctx.unique("hooks-libraries", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("hooks-libraries", l); ctx.stack_.push_back(l); @@ -380,6 +386,7 @@ hooks_param: library ; library: LIBRARY { + ctx.unique("library", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr lib(new StringElement($4, ctx.loc2pos(@4))); @@ -388,6 +395,7 @@ library: LIBRARY { }; parameters: PARAMETERS { + ctx.unique("parameters", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON map_value { ctx.stack_.back()->set("parameters", $4); @@ -398,6 +406,7 @@ parameters: PARAMETERS { // --- managed-servsers starts here --------------------------------------------- managed_servers: MANAGED_SERVERS COLON LCURLY_BRACKET { + ctx.unique("managed-servers", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("managed-servers", m); ctx.stack_.push_back(m); @@ -427,6 +436,7 @@ server_entry: dhcp4_server // That's an entry for dhcp4 server. dhcp4_server: DHCP4_SERVER { + ctx.unique("dhcp4", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("dhcp4", m); ctx.stack_.push_back(m); @@ -438,6 +448,7 @@ dhcp4_server: DHCP4_SERVER { // That's an entry for dhcp6 server. dhcp6_server: DHCP6_SERVER { + ctx.unique("dhcp6", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("dhcp6", m); ctx.stack_.push_back(m); @@ -449,6 +460,7 @@ dhcp6_server: DHCP6_SERVER { // That's an entry for d2 server. d2_server: D2_SERVER { + ctx.unique("d2", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("d2", m); ctx.stack_.push_back(m); @@ -460,6 +472,7 @@ d2_server: D2_SERVER { // That's an entry for ca server. ca_server: CA_SERVER { + ctx.unique("ca", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("ca", m); ctx.stack_.push_back(m); @@ -487,6 +500,7 @@ managed_server_param: model // YANG model model: MODEL { + ctx.unique("model", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr model(new StringElement($4, ctx.loc2pos(@4))); @@ -496,6 +510,7 @@ model: MODEL { // Control socket. control_socket: CONTROL_SOCKET { + ctx.unique("control-socket", ctx.loc2pos(@1)); ElementPtr m(new MapElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("control-socket", m); ctx.stack_.push_back(m); @@ -519,6 +534,7 @@ control_socket_param: socket_type ; socket_type: SOCKET_TYPE { + ctx.unique("socket-type", ctx.loc2pos(@1)); ctx.enter(ctx.SOCKET_TYPE); } COLON socket_type_value { ctx.stack_.back()->set("socket-type", $4); @@ -532,6 +548,7 @@ socket_type_value : UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos ; // Unix name. socket_name: SOCKET_NAME { + ctx.unique("socket-name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -541,6 +558,7 @@ socket_name: SOCKET_NAME { // HTTP url. socket_url: SOCKET_URL { + ctx.unique("socket-url", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr url(new StringElement($4, ctx.loc2pos(@4))); @@ -553,6 +571,7 @@ socket_url: SOCKET_URL { // --- Loggers starts here ----------------------------------------------------- loggers: LOGGERS { + ctx.unique("loggers", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("loggers", l); ctx.stack_.push_back(l); @@ -591,6 +610,7 @@ logger_param: name ; name: NAME { + ctx.unique("name", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr name(new StringElement($4, ctx.loc2pos(@4))); @@ -599,11 +619,13 @@ name: NAME { }; debuglevel: DEBUGLEVEL COLON INTEGER { + ctx.unique("debuglevel", ctx.loc2pos(@1)); ElementPtr dl(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("debuglevel", dl); }; severity: SEVERITY { + ctx.unique("severity", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -612,6 +634,7 @@ severity: SEVERITY { }; output_options_list: OUTPUT_OPTIONS { + ctx.unique("output_options", ctx.loc2pos(@1)); ElementPtr l(new ListElement(ctx.loc2pos(@1))); ctx.stack_.back()->set("output_options", l); ctx.stack_.push_back(l); @@ -645,6 +668,7 @@ output_params: output ; output: OUTPUT { + ctx.unique("output", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); @@ -653,21 +677,25 @@ output: OUTPUT { }; flush: FLUSH COLON BOOLEAN { + ctx.unique("flush", ctx.loc2pos(@1)); ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("flush", flush); }; maxsize: MAXSIZE COLON INTEGER { + ctx.unique("maxsize", ctx.loc2pos(@1)); ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxsize", maxsize); }; maxver: MAXVER COLON INTEGER { + ctx.unique("maxver", ctx.loc2pos(@1)); ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("maxver", maxver); }; pattern: PATTERN { + ctx.unique("pattern", ctx.loc2pos(@1)); ctx.enter(ctx.NO_KEYWORDS); } COLON STRING { ElementPtr sev(new StringElement($4, ctx.loc2pos(@4))); diff --git a/src/bin/netconf/parser_context.cc b/src/bin/netconf/parser_context.cc index 985d96084d..f435e85c58 100644 --- a/src/bin/netconf/parser_context.cc +++ b/src/bin/netconf/parser_context.cc @@ -159,7 +159,7 @@ ParserContext::contextName() case MANAGED_SERVERS: return ("managed-servers"); case SERVER: - return ("managed-servers/*"); + return ("managed-servers entry"); case CONTROL_SOCKET: return ("control-socket"); case SOCKET_TYPE: diff --git a/src/bin/netconf/tests/parser_unittests.cc b/src/bin/netconf/tests/parser_unittests.cc index 83ee2b8608..dfcb8a8690 100644 --- a/src/bin/netconf/tests/parser_unittests.cc +++ b/src/bin/netconf/tests/parser_unittests.cc @@ -673,6 +673,24 @@ TEST(ParserTest, errors) { " \"comment\": \"second\" }}\n", ParserContext::PARSER_NETCONF, ":2.23: syntax error, unexpected \",\", expecting }"); + + // duplicate of not string entries + testError("{ \"Netconf\":{\n" + " \"boot-update\": true,\n" + " \"boot-update\": false }}\n", + ParserContext::PARSER_NETCONF, + ":3:2: duplicate boot-update entries in " + "Netconf map (previous at :2:17)"); + + // duplicate of string entries + testError("{ \"Netconf\":{\n" + " \"managed-servers\": {\n" + " \"d2\": {\n" + " \"model\": \"foo\",\n" + " \"model\": \"bar\" }}}}\n", + ParserContext::PARSER_NETCONF, + ":5:7: duplicate model entries in " + "managed-servers entry map (previous at :4:16)"); } // Check unicode escapes