dhcp6_parser.yy 30.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* Copyright (C) 2015-2016 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/. */

%skeleton "lalr1.cc" /* -*- C++ -*- */
%require "3.0.0"
%defines
%define parser_class_name {Dhcp6Parser}
11
%define api.prefix {parser6_}
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
%define api.token.constructor
%define api.value.type variant
%define api.namespace {isc::dhcp}
%define parse.assert
%code requires
{
#include <string>
#include <cc/data.h>
#include <dhcp/option.h>
#include <boost/lexical_cast.hpp>
#include <dhcp6/parser_context_decl.h>

using namespace isc::dhcp;
using namespace isc::data;
using namespace std;
}
// The parsing context.
%param { isc::dhcp::Parser6Context& ctx }
%locations
%define parse.trace
%define parse.error verbose
%code
{
#include <dhcp6/parser_context.h>

}

39

40
41
42
43
44
45
46
47
48
49
50
%define api.token.prefix {TOKEN_}
// Tokens in an order which makes sense and related to the intented use.
%token
  END  0  "end of file"
  COMMA ","
  COLON ":"
  LSQUARE_BRACKET "["
  RSQUARE_BRACKET "]"
  LCURLY_BRACKET "{"
  RCURLY_BRACKET "}"
  NULL_TYPE "null"
51
52
53
54

  DHCP6 "Dhcp6"
  INTERFACES_CONFIG "interfaces-config"
  INTERFACES "interfaces"
55

56
  LEASE_DATABASE "lease-database"
57
  HOSTS_DATABASE "hosts-database"
58
  TYPE "type"
59
60
61
  USER "user"
  PASSWORD "password"
  HOST "host"
62
  PERSIST "persist"
63
  LFC_INTERVAL "lfc-interval"
64

65
66
67
68
69
70
71
72
73
  PREFERRED_LIFETIME "preferred-lifetime"
  VALID_LIFETIME "valid-lifetime"
  RENEW_TIMER "renew-timer"
  REBIND_TIMER "rebind-timer"
  SUBNET6 "subnet6"
  OPTION_DATA "option-data"
  NAME "name"
  DATA "data"
  CODE "code"
74
  SPACE "space"
75
  CSV_FORMAT "csv-format"
76

77
78
  POOLS "pools"
  POOL "pool"
79
80
81
82
83
  PD_POOLS "pd-pools"
  PREFIX "prefix"
  PREFIX_LEN "prefix-len"
  DELEGATED_LEN "delegated-len"

84
85
  SUBNET "subnet"
  INTERFACE "interface"
86
  ID "id"
87

88
89
  MAC_SOURCES "mac-sources"
  RELAY_SUPPLIED_OPTIONS "relay-supplied-options"
90
  HOST_RESERVATION_IDENTIFIERS "host-reservation-identifiers"
91

92
93
94
95
96
  CLIENT_CLASSES "client-classes"
  TEST "test"
  CLIENT_CLASS "client-class"

  RESERVATIONS "reservations"
97
98
  IP_ADDRESSES "ip-addresses"
  PREFIXES "prefixes"
99
  DUID "duid"
100
101
  HW_ADDRESS "hw-address"
  HOSTNAME "hostname"
102

103
104
105
106
107
108
109
110
111
  HOOKS_LIBRARIES "hooks-libraries"
  LIBRARY "library"

  EXPIRED_LEASES_PROCESSING "expired-leases-processing"

  SERVER_ID "server-id"
  IDENTIFIER "identifier"
  HTYPE "htype"
  TIME "time"
112
  ENTERPRISE_ID "enterprise-id"
113

114
115
  DHCP4O6_PORT "dhcp4o6-port"

116
117
118
119
120
121
  LOGGING "Logging"
  LOGGERS "loggers"
  OUTPUT_OPTIONS "output_options"
  OUTPUT "output"
  DEBUGLEVEL "debuglevel"
  SEVERITY "severity"
122

123
124
125
126
  DHCP_DDNS "dhcp-ddns"
  ENABLE_UPDATES "enable-updates"
  QUALIFYING_SUFFIX "qualifying-suffix"

127
128
129
 // Not real tokens, just a way to signal what the parser is expected to
 // parse.
  TOPLEVEL_GENERIC_JSON
130
  TOPLEVEL_DHCP6
131
132
133
134
135
136
137
138
139
140
141
142
;

%token <std::string> STRING "constant string"
%token <int64_t> INTEGER "integer"
%token <double> FLOAT "floating point"
%token <bool> BOOLEAN "boolean"

%type <ElementPtr> value

%printer { yyoutput << $$; } <*>;

%%
143

144
145
// The whole grammar starts with a map, because the config file
// constists of Dhcp, Logger and DhcpDdns entries in one big { }.
146
147
// %start map - this will parse everything as generic JSON
// %start dhcp6_map - this will parse everything with Dhcp6 syntax checking
148
149
%start start;

150
151
152
start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2
     | TOPLEVEL_DHCP6 { ctx.ctx_ = ctx.CONFIG; } syntax_map
     ;
153

154
155
// ---- generic JSON parser ---------------------------------

156
157
// Note that ctx_ is NO_KEYWORD here

158
// Values rule
159
160
161
162
163
164
165
166
value: INTEGER { $$ = ElementPtr(new IntElement($1)); }
     | FLOAT { $$ = ElementPtr(new DoubleElement($1)); }
     | BOOLEAN { $$ = ElementPtr(new BoolElement($1)); }
     | STRING { $$ = ElementPtr(new StringElement($1)); }
     | NULL_TYPE { $$ = ElementPtr(new NullElement()); }
     | map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
     | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
     ;
167

168
map2: LCURLY_BRACKET {
169
170
171
172
173
174
175
176
177
    // This code is executed when we're about to start parsing
    // the content of the map
    ElementPtr m(new MapElement());
    ctx.stack_.push_back(m);
} map_content RCURLY_BRACKET {
    // map parsing completed. If we ever want to do any wrap up
    // (maybe some sanity checking), this would be the best place
    // for it.
};
178
179

// Assignments rule
180
map_content: %empty // empty map
181
182
183
184
185
186
187
188
189
190
           | STRING COLON value {
               // map containing a single entry
               ctx.stack_.back()->set($1, $3);
               }
           | map_content COMMA STRING COLON value {
               // map consisting of a shorter map followed by
               // comma and string:value
               ctx.stack_.back()->set($3, $5);
               }
           ;
191

192
193
194
list_generic: LSQUARE_BRACKET {
    ElementPtr l(new ListElement());
    ctx.stack_.push_back(l);
195
196
197
} list_content RSQUARE_BRACKET {
    // list parsing complete. Put any sanity checking here
};
198
199
200

// This one is used in syntax parser.
list2: LSQUARE_BRACKET {
201
202
203
    // List parsing about to start
} list_content RSQUARE_BRACKET {
    // list parsing complete. Put any sanity checking here
204
    //ctx.stack_.pop_back();
205
};
206

207
list_content: %empty // Empty list
208
209
210
211
212
213
214
215
216
            | value {
                // List consisting of a single element.
                ctx.stack_.back()->add($1);
                }
            | list_content COMMA value {
                // List ending with , and a value.
                ctx.stack_.back()->add($3);
                }
            ;
217

218
219
220
221
222
223
// ---- generic JSON parser ends here ----------------------------------

// ---- syntax checking parser starts here -----------------------------

// This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging
// objects.
224
// ctx_ = CONFIG
225
226
227
228
229
230
231
232
233
234
235
236
237
syntax_map: LCURLY_BRACKET {
    // This code is executed when we're about to start parsing
    // the content of the map
    ElementPtr m(new MapElement());
    ctx.stack_.push_back(m);
} global_objects RCURLY_BRACKET {
    // map parsing completed. If we ever want to do any wrap up
    // (maybe some sanity checking), this would be the best place
    // for it.
};

// This represents a single top level entry, e.g. Dhcp6 or DhcpDdns.
global_object: dhcp6_object
238
239
             | logging_object
             ;
240
241

// This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
242
243
244
global_objects: global_object
              | global_objects COMMA global_object
              ;
245

246
dhcp6_object: DHCP6 {
247
248
249
250
251
    // This code is executed when we're about to start parsing
    // the content of the map
    ElementPtr m(new MapElement());
    ctx.stack_.back()->set("Dhcp6", m);
    ctx.stack_.push_back(m);
252
253
    ctx.enter(ctx.DHCP6);
} COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
254
255
256
257
    // map parsing completed. If we ever want to do any wrap up
    // (maybe some sanity checking), this would be the best place
    // for it.
    ctx.stack_.pop_back();
258
    ctx.leave();
259
260
};

261
global_params: global_param
262
263
             | global_params COMMA global_param
             ;
264
265

// These are the parameters that are allowed in the top-level for
266
// Dhcp6.
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
global_param: preferred_lifetime
            | valid_lifetime
            | renew_timer
            | rebind_timer
            | subnet6_list
            | interfaces_config
            | lease_database
            | hosts_database
            | mac_sources
            | relay_supplied_options
            | host_reservation_identifiers
            | client_classes
            | option_data_list
            | hooks_libraries
            | expired_leases_processing
            | server_id
            | dhcp4o6_port
            | dhcp_ddns
            ;
286
287

preferred_lifetime: PREFERRED_LIFETIME COLON INTEGER {
288
289
    ElementPtr prf(new IntElement($3));
    ctx.stack_.back()->set("preferred-lifetime", prf);
290
291
292
};

valid_lifetime: VALID_LIFETIME COLON INTEGER {
293
294
    ElementPtr prf(new IntElement($3));
    ctx.stack_.back()->set("valid-lifetime", prf);
295
296
297
};

renew_timer: RENEW_TIMER COLON INTEGER {
298
299
    ElementPtr prf(new IntElement($3));
    ctx.stack_.back()->set("renew-timer", prf);
300
301
};

302
303
304
305
rebind_timer: REBIND_TIMER COLON INTEGER {
    ElementPtr prf(new IntElement($3));
    ctx.stack_.back()->set("rebind-timer", prf);
};
306

307
interfaces_config: INTERFACES_CONFIG {
308
309
310
    ElementPtr i(new MapElement());
    ctx.stack_.back()->set("interfaces-config", i);
    ctx.stack_.push_back(i);
311
312
    ctx.enter(ctx.INTERFACES_CONFIG);
} COLON LCURLY_BRACKET interface_config_map RCURLY_BRACKET {
313
    ctx.stack_.pop_back();
314
    ctx.leave();
315
};
316

317
318
319
320
interface_config_map: INTERFACES {
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("interfaces", l);
    ctx.stack_.push_back(l);
321
322
323
324
325
    ctx.enter(ctx.NO_KEYWORD);
} COLON list2 {
    ctx.stack_.pop_back();
    ctx.leave();
};
326
327
328
329
330

lease_database: LEASE_DATABASE {
    ElementPtr i(new MapElement());
    ctx.stack_.back()->set("lease-database", i);
    ctx.stack_.push_back(i);
331
332
333
334
335
    ctx.enter(ctx.DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
    ctx.leave();
};
336

337
338
339
340
hosts_database: HOSTS_DATABASE {
    ElementPtr i(new MapElement());
    ctx.stack_.back()->set("hosts-database", i);
    ctx.stack_.push_back(i);
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
    ctx.enter(ctx.DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
    ctx.leave();
};

database_map_params: database_map_param
                   | database_map_params COMMA database_map_param
                   ;

database_map_param: type
                  | user
                  | password
                  | host
                  | name
                  | persist
                  | lfc_interval;
358
;
359

360
361
362
363
type: TYPE {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr prf(new StringElement($4));
364
    ctx.stack_.back()->set("type", prf);
365
    ctx.leave();
366
367
};

368
369
370
371
user: USER {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr user(new StringElement($4));
372
    ctx.stack_.back()->set("user", user);
373
    ctx.leave();
374
375
};

376
377
378
379
password: PASSWORD {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr pwd(new StringElement($4));
380
    ctx.stack_.back()->set("password", pwd);
381
    ctx.leave();
382
383
};

384
385
386
387
host: HOST {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr h(new StringElement($4));
388
    ctx.stack_.back()->set("host", h);
389
    ctx.leave();
390
391
};

392
393
394
name: NAME {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
395
396
    ElementPtr name(new StringElement($4));
    ctx.stack_.back()->set("name", name);
397
    ctx.leave();
398
399
};

400
401
402
403
404
persist: PERSIST COLON BOOLEAN {
    ElementPtr n(new BoolElement($3));
    ctx.stack_.back()->set("persist", n);
};

405
406
407
408
409
lfc_interval: LFC_INTERVAL COLON INTEGER {
    ElementPtr n(new IntElement($3));
    ctx.stack_.back()->set("lfc-interval", n);
};

410
411
412
413
mac_sources: MAC_SOURCES {
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("mac-sources", l);
    ctx.stack_.push_back(l);
414
    ctx.enter(ctx.MAC_SOURCES);
415
} COLON LSQUARE_BRACKET mac_sources_list RSQUARE_BRACKET {
416
    ctx.stack_.pop_back();
417
    ctx.leave();
418
419
};

420
mac_sources_list: mac_sources_value
421
422
                | mac_sources_list COMMA mac_sources_value
;
423

424
425
mac_sources_value: duid_id
                 | string_id
426
427
                 ;

428
429
430
431
432
433
434
435
436
437
duid_id : DUID {
    ElementPtr duid(new StringElement("duid"));
    ctx.stack_.back()->add(duid);
};

string_id : STRING {
    ElementPtr duid(new StringElement($1));
    ctx.stack_.back()->add(duid);
};

438
host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS {
439
440
441
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("host-reservation-identifiers", l);
    ctx.stack_.push_back(l);
442
443
    ctx.enter(ctx.HOST_RESERVATION_IDENTIFIERS);    
} COLON LSQUARE_BRACKET host_reservation_identifiers_list RSQUARE_BRACKET {
444
    ctx.stack_.pop_back();
445
    ctx.leave();
446
447
448
};

host_reservation_identifiers_list: host_reservation_identifier
449
450
    | host_reservation_identifiers_list COMMA host_reservation_identifier
    ;
451

452
453
host_reservation_identifier: duid_id
                           | hw_address_id
454
                           ;
455

456
457
458
459
460
hw_address_id : HW_ADDRESS {
    ElementPtr hwaddr(new StringElement("hw-address"));
    ctx.stack_.back()->add(hwaddr);
};

461
462
463
464
relay_supplied_options: RELAY_SUPPLIED_OPTIONS {
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("relay-supplied-options", l);
    ctx.stack_.push_back(l);
465
    ctx.enter(ctx.NO_KEYWORD);
466
} COLON list2 {
467
    ctx.stack_.pop_back();
468
    ctx.leave();
469
470
};

471
hooks_libraries: HOOKS_LIBRARIES {
472
473
474
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("hooks-libraries", l);
    ctx.stack_.push_back(l);
475
476
    ctx.enter(ctx.HOOKS_LIBRARIES);
} COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET {
477
    ctx.stack_.pop_back();
478
    ctx.leave();
479
480
};

481
hooks_libraries_list: %empty
482
483
484
                    | hooks_library
                    | hooks_libraries_list COMMA hooks_library
                    ;
485
486
487
488
489
490
491
492
493
494

hooks_library: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} hooks_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};

hooks_params: hooks_param
495
496
            | hooks_params hooks_param
            ;
497

498
499
500
501
502
503
hooks_param: LIBRARY {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr lib(new StringElement($4));
    ctx.stack_.back()->set("library", lib);
    ctx.leave(); 
504
505
506
};

// --- expired-leases-processing ------------------------
507
expired_leases_processing: EXPIRED_LEASES_PROCESSING {
508
509
510
    ElementPtr m(new MapElement());
    ctx.stack_.back()->set("expired-leases-processing", m);
    ctx.stack_.push_back(m);
511
512
    ctx.enter(ctx.NO_KEYWORD);
} COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
513
    ctx.stack_.pop_back();
514
    ctx.leave();
515
516
517
};

expired_leases_params: expired_leases_param
518
519
                     | expired_leases_params COMMA expired_leases_param
                     ;
520
521
522
523
524

// This is a bit of a simplification. But it can also serve as an example.
// Instead of explicitly listing all allowed expired leases parameters, we
// simply say that all of them as integers.
expired_leases_param: STRING COLON INTEGER {
525
526
    ElementPtr value(new IntElement($3));
    ctx.stack_.back()->set($1, value);
527
528
529
}

// --- subnet6 ------------------------------------------
530
531
// This defines subnet6 as a list of maps.
// "subnet6": [ ... ]
532
subnet6_list: SUBNET6 {
533
    ElementPtr l(new ListElement());
534
    ctx.stack_.back()->set("subnet6", l);
535
    ctx.stack_.push_back(l);
536
537
    ctx.enter(ctx.SUBNET6);
} COLON LSQUARE_BRACKET subnet6_list_content RSQUARE_BRACKET {
538
    ctx.stack_.pop_back();
539
    ctx.leave();
540
541
542
543
544
};

// This defines the ... in "subnet6": [ ... ]
// It can either be empty (no subnets defined), have one subnet
// or have multiple subnets separate by comma.
545
subnet6_list_content: %empty
546
547
548
                    | subnet6
                    | subnet6_list_content COMMA subnet6
                    ;
549

550
551
// --- Subnet definitions -------------------------------

552
553
// This defines a single subnet, i.e. a single map with
// subnet6 array.
554
555
556
557
subnet6: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
558
} subnet6_params RCURLY_BRACKET {
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    // Once we reached this place, the subnet parsing is now complete.
    // If we want to, we can implement default values here.
    // In particular we can do things like this:
    // if (!ctx.stack_.back()->get("interface")) {
    //     ctx.stack_.back()->set("interface", StringElement("loopback"));
    // }
    //
    // We can also stack up one level (Dhcp6) and copy over whatever
    // global parameters we want to:
    // if (!ctx.stack_.back()->get("renew-timer")) {
    //     ElementPtr renew = ctx_stack_[...].get("renew-timer");
    //     if (renew) {
    //         ctx.stack_.back()->set("renew-timer", renew);
    //     }
    // }
574
    ctx.stack_.pop_back();
575
};
576

577
// This defines that subnet can have one or more parameters.
578
subnet6_params: subnet6_param
579
580
              | subnet6_params COMMA subnet6_param
              ;
581

582
583
// This defines a list of allowed parameters for each subnet.
subnet6_param: option_data_list
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
             | pools_list
             | pd_pools_list
             | subnet
             | interface
             | id
             | client_class
             | reservations
             ;

subnet: SUBNET {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr subnet(new StringElement($4));
    ctx.stack_.back()->set("subnet", subnet);
    ctx.leave();
};

interface: INTERFACE {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr iface(new StringElement($4));
    ctx.stack_.back()->set("interface", iface);
    ctx.leave();
};

client_class: CLIENT_CLASS {
    ctx.enter(ctx.CLIENT_CLASS);
} COLON STRING {
    ElementPtr cls(new StringElement($4));
    ctx.stack_.back()->set("client-class", cls);
    ctx.leave();
615
616
};

617
id: ID COLON INTEGER {
618
619
    ElementPtr id(new IntElement($3));
    ctx.stack_.back()->set("id", id);
620
};
621

622
623
624
625
// ---- option-data --------------------------

// This defines the "option-data": [ ... ] entry that may appear
// in several places, but most notably in subnet6 entries.
626
627
628
629
option_data_list: OPTION_DATA {
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("option-data", l);
    ctx.stack_.push_back(l);
630
    ctx.enter(ctx.OPTION_DATA);
631
632
} COLON LSQUARE_BRACKET option_data_list_content RSQUARE_BRACKET {
    ctx.stack_.pop_back();
633
    ctx.leave();
634
};
635
636
637

// This defines the content of option-data. It may be empty,
// have one entry or multiple entries separated by comma.
638
option_data_list_content: %empty
639
640
641
                        | option_data_entry
                        | option_data_list_content COMMA option_data_entry
                        ;
642
643
644

// This defines th content of a single entry { ... } within
// option-data list.
645
646
647
648
649
650
651
option_data_entry: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} option_data_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};
652
653
654

// This defines parameters specified inside the map that itself
// is an entry in option-data list.
655
option_data_params: option_data_param
656
657
                  | option_data_params COMMA option_data_param
                  ;
658

659
option_data_param: %empty
660
661
662
663
664
665
666
667
                 | option_data_name
                 | option_data_data
                 | option_data_code
                 | option_data_space
                 | option_data_csv_format
                 ;


668
option_data_name: name;
669

670
671
672
673
674
675
option_data_data: DATA {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr data(new StringElement($4));
    ctx.stack_.back()->set("data", data);
    ctx.leave();
676
677
678
};

option_data_code: CODE COLON INTEGER {
679
680
    ElementPtr code(new IntElement($3));
    ctx.stack_.back()->set("code", code);
681
};
682

683
684
685
686
687
688
option_data_space: SPACE {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr space(new StringElement($4));
    ctx.stack_.back()->set("space", space);
    ctx.leave();
689
690
};

691
option_data_csv_format: CSV_FORMAT COLON BOOLEAN {
692
693
    ElementPtr space(new BoolElement($3));
    ctx.stack_.back()->set("csv-format", space);
694
695
};

696
697
698
// ---- pools ------------------------------------

// This defines the "pools": [ ... ] entry that may appear in subnet6.
699
pools_list: POOLS {
700
701
702
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("pools", l);
    ctx.stack_.push_back(l);
703
704
    ctx.enter(ctx.POOLS);
} COLON LSQUARE_BRACKET pools_list_content RSQUARE_BRACKET {
705
    ctx.stack_.pop_back();
706
    ctx.leave();
707
};
708
709
710

// Pools may be empty, contain a single pool entry or multiple entries
// separate by commas.
711
pools_list_content: %empty
712
713
714
                  | pool_list_entry
                  | pools_list_content COMMA pool_list_entry
                  ;
715

716
pool_list_entry: LCURLY_BRACKET {
717
718
719
720
721
722
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} pool_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};
723
724

pool_params: pool_param
725
726
727
728
729
730
731
732
733
734
735
736
737
738
           | pool_params COMMA pool_param
           ;

pool_param: pool_entry
          | option_data_list
          ;

pool_entry: POOL {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr pool(new StringElement($4));
    ctx.stack_.back()->set("pool", pool);
    ctx.leave();
};
739

740
741
// --- end of pools definition -------------------------------

742
// --- pd-pools ----------------------------------------------
743
pd_pools_list: PD_POOLS {
744
745
746
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("pd-pools", l);
    ctx.stack_.push_back(l);
747
748
    ctx.enter(ctx.PD_POOLS);
} COLON LSQUARE_BRACKET pd_pools_list_content RSQUARE_BRACKET {
749
    ctx.stack_.pop_back();
750
    ctx.leave();
751
752
753
754
};

// Pools may be empty, contain a single pool entry or multiple entries
// separate by commas.
755
pd_pools_list_content: %empty
756
757
758
                     | pd_pool_entry
                     | pd_pools_list_content COMMA pd_pool_entry
                     ;
759
760
761
762
763
764
765
766
767
768

pd_pool_entry: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} pd_pool_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};

pd_pool_params: pd_pool_param
769
770
              | pd_pool_params COMMA pd_pool_param
              ;
771
772

pd_pool_param: pd_prefix
773
774
775
776
777
778
779
780
781
782
783
             | pd_prefix_len
             | pd_delegated_len
             | option_data_list
             ;

pd_prefix: PREFIX {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr prf(new StringElement($4));
    ctx.stack_.back()->set("prefix", prf);
    ctx.leave();
784
785
786
}

pd_prefix_len: PREFIX_LEN COLON INTEGER {
787
788
    ElementPtr prf(new IntElement($3));
    ctx.stack_.back()->set("prefix-len", prf);
789
790
791
}

pd_delegated_len: DELEGATED_LEN COLON INTEGER {
792
793
    ElementPtr deleg(new IntElement($3));
    ctx.stack_.back()->set("delegated-len", deleg);
794
795
796
797
}

// --- end of pd-pools ---------------------------------------

798
// --- reservations ------------------------------------------
799
reservations: RESERVATIONS {
800
801
802
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("reservations", l);
    ctx.stack_.push_back(l);
803
804
    ctx.enter(ctx.RESERVATIONS);
} COLON LSQUARE_BRACKET reservations_list RSQUARE_BRACKET {
805
    ctx.stack_.pop_back();
806
807
    ctx.leave();
};
808

809
reservations_list: %empty
810
811
812
                 | reservation
                 | reservations_list COMMA reservation
                 ;
813
814
815
816
817
818
819
820
821
822

reservation: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} reservation_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};

reservation_params: reservation_param
823
824
                  | reservation_params COMMA reservation_param
                  ;
825
826

// @todo probably need to add mac-address as well here
827
reservation_param: %empty
828
829
830
831
832
833
834
835
836
837
                 | duid
                 | reservation_client_classes
                 | ip_addresses
                 | prefixes
                 | hw_address
                 | hostname
                 | option_data_list
                 ;

ip_addresses: IP_ADDRESSES {
838
839
840
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("ip-addresses", l);
    ctx.stack_.push_back(l);
841
842
    ctx.enter(ctx.NO_KEYWORD);
} COLON list2 {
843
    ctx.stack_.pop_back();
844
    ctx.leave();
845
846
};

847
prefixes: PREFIXES  {
848
849
850
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("prefixes", l);
    ctx.stack_.push_back(l);
851
852
    ctx.enter(ctx.NO_KEYWORD);
} COLON list2 {
853
    ctx.stack_.pop_back();
854
    ctx.leave();
855
856
};

857
858
859
860
861
862
duid: DUID {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr d(new StringElement($4));
    ctx.stack_.back()->set("duid", d);
    ctx.leave();
863
864
};

865
866
867
868
869
870
hw_address: HW_ADDRESS {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr hw(new StringElement($4));
    ctx.stack_.back()->set("hw-address", hw);
    ctx.leave();
871
872
};

873
874
875
876
877
878
hostname: HOSTNAME {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr host(new StringElement($4));
    ctx.stack_.back()->set("hostname", host);
    ctx.leave();
879
880
}

881
reservation_client_classes: CLIENT_CLASSES {
882
883
884
    ElementPtr c(new ListElement());
    ctx.stack_.back()->set("client-classes", c);
    ctx.stack_.push_back(c);
885
886
    ctx.enter(ctx.NO_KEYWORD);
} COLON list2 {
887
    ctx.stack_.pop_back();
888
889
    ctx.leave();
};
890
891
892
893

// --- end of reservations definitions -----------------------

// --- client classes ----------------------------------------
894
client_classes: CLIENT_CLASSES {
895
896
897
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("client-classes", l);
    ctx.stack_.push_back(l);
898
899
    ctx.enter(ctx.CLIENT_CLASSES);
} COLON LSQUARE_BRACKET client_classes_list RSQUARE_BRACKET {
900
    ctx.stack_.pop_back();
901
    ctx.leave();
902
903
904
};

client_classes_list: client_class
905
906
                   | client_classes_list COMMA client_class
                   ;
907
908
909
910
911
912
913
914
915
916

client_class: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} client_class_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};

client_class_params: client_class_param
917
918
                   | client_class_params COMMA client_class_param
                   ;
919

920
client_class_param: %empty
921
922
923
924
925
                  | client_class_name
                  | client_class_test
                  | option_data_list
                  ;

926
client_class_name: name;
927

928
929
930
931
client_class_test: TEST {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr test(new StringElement($4));
932
    ctx.stack_.back()->set("test", test);
933
    ctx.leave();
934
935
936
937
938
}


// --- end of client classes ---------------------------------

939
// --- server-id ---------------------------------------------
940
server_id: SERVER_ID {
941
942
943
    ElementPtr m(new MapElement());
    ctx.stack_.back()->set("server-id", m);
    ctx.stack_.push_back(m);
944
945
    ctx.enter(ctx.SERVER_ID);
} COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET {
946
    ctx.stack_.pop_back();
947
    ctx.leave();
948
949
950
};

server_id_params: server_id_param
951
952
                | server_id_params COMMA server_id_param
                ;
953
954

server_id_param: type
955
956
957
958
959
960
               | identifier
               | time
               | htype
               | enterprise_id
               | persist
               ;
961
962
963
964
965
966

htype: HTYPE COLON INTEGER {
    ElementPtr htype(new IntElement($3));
    ctx.stack_.back()->set("htype", htype);
};

967
968
969
970
identifier: IDENTIFIER {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr id(new StringElement($4));
971
    ctx.stack_.back()->set("identifier", id);
972
    ctx.leave();
973
974
975
976
977
978
};

time: TIME COLON INTEGER {
    ElementPtr time(new IntElement($3));
    ctx.stack_.back()->set("time", time);
};
979
980
981
982
983
984

enterprise_id: ENTERPRISE_ID COLON INTEGER {
    ElementPtr time(new IntElement($3));
    ctx.stack_.back()->set("enterprise-id", time);
};

985
986
// --- end of server-id --------------------------------------

987
988
989
990
991
dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
    ElementPtr time(new IntElement($3));
    ctx.stack_.back()->set("dhcp4o6-port", time);
};

992
993
994
995
996
// --- logging entry -----------------------------------------

// This defines the top level "Logging" object. It parses
// the following "Logging": { ... }. The ... is defined
// by logging_params
997
logging_object: LOGGING {
998
999
1000
    ElementPtr m(new MapElement());
    ctx.stack_.back()->set("Logging", m);
    ctx.stack_.push_back(m);
1001
1002
    ctx.enter(ctx.LOGGING);
} COLON LCURLY_BRACKET logging_params RCURLY_BRACKET {
1003
    ctx.stack_.pop_back();
1004
    ctx.leave();
1005
1006
1007
1008
1009
1010
};

// This defines the list of allowed parameters that may appear
// in the top-level Logging object. It can either be a single
// parameter or several parameters separated by commas.
logging_params: logging_param
1011
1012
              | logging_params COMMA logging_param
              ;
1013
1014
1015
1016
1017
1018

// There's currently only one parameter defined, which is "loggers".
logging_param: loggers;

// "loggers", the only parameter currently defined in "Logging" object,
// is "Loggers": [ ... ].
1019
loggers: LOGGERS {
1020
1021
1022
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("loggers", l);
    ctx.stack_.push_back(l);
1023
1024
    ctx.enter(ctx.LOGGERS);
}  COLON LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET {
1025
    ctx.stack_.pop_back();
1026
    ctx.leave();
1027
};
1028
1029
1030
1031

// These are the parameters allowed in loggers: either one logger
// entry or multiple entries separate by commas.
loggers_entries: logger_entry
1032
1033
               | loggers_entries COMMA logger_entry
               ;
1034
1035

// This defines a single entry defined in loggers in Logging.
1036
1037
1038
1039
1040
1041
1042
logger_entry: LCURLY_BRACKET {
    ElementPtr l(new MapElement());
    ctx.stack_.back()->add(l);
    ctx.stack_.push_back(l);
} logger_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};
1043
1044

logger_params: logger_param
1045
1046
             | logger_params COMMA logger_param
             ;
1047

1048
logger_param: name
1049
1050
1051
1052
1053
            | output_options_list
            | debuglevel
            | severity
            ;

1054
debuglevel: DEBUGLEVEL COLON INTEGER {
1055
1056
    ElementPtr dl(new IntElement($3));
    ctx.stack_.back()->set("debuglevel", dl);
1057
};
1058
1059
1060
1061
1062
1063
severity: SEVERITY {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr sev(new StringElement($4));
    ctx.stack_.back()->set("severity", sev);
    ctx.leave();
1064
};
1065

1066
output_options_list: OUTPUT_OPTIONS {
1067
1068
1069
    ElementPtr l(new ListElement());
    ctx.stack_.back()->set("output_options", l);
    ctx.stack_.push_back(l);
1070
1071
    ctx.enter(ctx.OUTPUT_OPTIONS);
} COLON LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET {
1072
    ctx.stack_.pop_back();
1073
    ctx.leave();
1074
};
1075
1076

output_options_list_content: output_entry
1077
1078
                           | output_options_list_content COMMA output_entry
                           ;
1079

1080
1081
1082
1083
1084
1085
1086
output_entry: LCURLY_BRACKET {
    ElementPtr m(new MapElement());
    ctx.stack_.back()->add(m);
    ctx.stack_.push_back(m);
} output_params RCURLY_BRACKET {
    ctx.stack_.pop_back();
};
1087
1088

output_params: output_param
1089
1090
             | output_params COMMA output_param
             ;
1091

1092
1093
1094
1095
1096
1097
output_param: OUTPUT {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr sev(new StringElement($4));
    ctx.stack_.back()->set("output", sev);
    ctx.leave();
1098
};
1099

1100
dhcp_ddns: DHCP_DDNS {
1101
1102
1103
    ElementPtr m(new MapElement());
    ctx.stack_.back()->set("dhcp-ddns", m);
    ctx.stack_.push_back(m);
1104
1105
    ctx.enter(ctx.DHCP_DDNS);
} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
1106
    ctx.stack_.pop_back();
1107
    ctx.leave();
1108
1109
1110
};

dhcp_ddns_params: dhcp_ddns_param
1111
1112
                | dhcp_ddns_params COMMA dhcp_ddns_param
                ;
1113
1114

dhcp_ddns_param: enable_updates
1115
1116
               | qualifying_suffix
               ;
1117

1118
1119
1120
1121
1122
enable_updates: ENABLE_UPDATES COLON BOOLEAN {
    ElementPtr b(new BoolElement($3));
    ctx.stack_.back()->set("enable-updates", b);
};

1123
1124
1125
1126
qualifying_suffix: QUALIFYING_SUFFIX {
    ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
    ElementPtr qs(new StringElement($4));
1127
    ctx.stack_.back()->set("qualifying-suffix", qs);
1128
    ctx.leave();
1129
};
1130

1131
1132
1133
1134
%%

void
isc::dhcp::Dhcp6Parser::error(const location_type& loc,
1135
                              const std::string& what)
1136
1137
1138
{
    ctx.error(loc, what);
}