2 * BIRD -- Configuration Parser Top
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
13 #include "nest/bird.h"
14 #include "conf/conf.h"
15 #include "lib/resource.h"
16 #include "lib/socket.h"
17 #include "lib/timer.h"
18 #include "lib/string.h"
19 #include "nest/protocol.h"
20 #include "nest/iface.h"
21 #include "nest/route.h"
24 #include "filter/filter.h"
26 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
34 cf_error("Value %u out of range (0-65535)", val);
37 #define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
38 static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
40 case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break;
41 case SYM_TEMPLATE: cf_assert(sym->class == SYM_TEMPLATE, "Protocol template name required"); break;
42 case SYM_FUNCTION: cf_assert(sym->class == SYM_FUNCTION, "Function name required"); break;
43 case SYM_FILTER: cf_assert(sym->class == SYM_FILTER, "Filter name required"); break;
44 case SYM_TABLE: cf_assert(sym->class == SYM_TABLE, "Table name required"); break;
45 case SYM_ATTRIBUTE: cf_assert(sym->class == SYM_ATTRIBUTE, "Custom attribute name required"); break;
46 case SYM_MPLS_DOMAIN: cf_assert(sym->class == SYM_MPLS_DOMAIN, "MPLS domain name required"); break;
47 case SYM_MPLS_RANGE: cf_assert(sym->class == SYM_MPLS_RANGE, "MPLS range name required"); break;
48 case SYM_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break;
49 case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break;
50 default: bug("This shall not happen");
68 struct rtable_config *r;
69 struct channel_config *cc;
73 struct f_inst *begin, *end;
75 enum filter_return fret;
77 struct f_dynamic_attr fda;
78 struct f_static_attr fsa;
82 const struct filter *f;
86 struct password_item *p;
87 struct rt_show_data *ra;
88 struct sym_show_data *sd;
89 struct lsadb_show_data *ld;
90 struct mrt_dump_data *md;
96 struct channel_limit cl;
97 struct timeformat *tf;
98 mpls_label_stack *mls;
99 const struct adata *bs;
100 struct aggr_item_node *ai;
103 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
104 %token GEQ LEQ NEQ AND OR IMP
110 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS
113 %type <iface> ipa_scope
115 %type <i> expr bool pxlen4
116 %type <time> expr_us time
118 %type <net> net_ip4_ net_ip4 net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
119 %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
120 %type <mls> label_stack_start label_stack
122 %type <t> text opttext
123 %type <bs> bytestring
124 %type <s> symbol symbol_known
126 %type <v> bytestring_text text_or_ipa
127 %type <x> bytestring_expr
129 %nonassoc PREFIX_DUMMY
131 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA IMP PO PC
139 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM, MAX, AS)
143 /* Basic config file structure */
145 config: conf_entries END { return 0; }
146 | CLI_MARKER cli_cmd { return 0; }
157 /* Constant expressions */
162 DEFINE symbol '=' term ';' {
163 struct f_val *val = cfg_allocz(sizeof(struct f_val));
164 *val = cf_eval($4, T_VOID);
165 cf_define_symbol(new_config, $2, SYM_CONSTANT | val->type, val, val);
171 | '(' term ')' { $$ = cf_eval_int($2); }
173 if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
174 $$ = SYM_VAL($1).i; }
178 expr S { $$ = $1 S_; }
179 | expr MS { $$ = $1 MS_; }
180 | expr US { $$ = $1 US_; }
183 symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD ;
184 symbol_known: CF_SYM_KNOWN ;
194 | /* Silence means agreement */ { $$ = 1; }
201 IP4 { $$ = ipa_from_ip4($1); }
202 | IP6 { $$ = ipa_from_ip6($1); }
204 if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
210 /* empty */ { $$ = NULL; }
211 | '%' symbol { $$ = if_get_by_name($2->name); }
215 /* Networks - internal */
219 if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
226 net_fill_ip4(&($$), $1, $2);
228 net_addr_ip4 *n = (void *) &($$);
229 if (!net_validate_ip4(n))
230 cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
231 n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
234 net_ip6_: IP6 '/' NUM
236 if ($3 > IP6_MAX_PREFIX_LENGTH)
237 cf_error("Invalid prefix length %u", $3);
239 net_fill_ip6(&($$), $1, $3);
241 net_addr_ip6 *n = (void *) &($$);
242 if (!net_validate_ip6(n))
243 cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
244 n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
247 net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
249 if ($3 > IP6_MAX_PREFIX_LENGTH)
250 cf_error("Invalid prefix length %u", $3);
252 if ($7 > IP6_MAX_PREFIX_LENGTH)
253 cf_error("Invalid prefix length %u", $7);
255 $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
256 net_fill_ip6_sadr($$, $1, $3, $5, $7);
258 net_addr_ip6_sadr *n = (void *) $$;
259 if (!net_validate_ip6_sadr(n))
260 cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
261 n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
262 ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
263 ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
266 net_vpn4_: VPN_RD net_ip4_
268 $$ = cfg_alloc(sizeof(net_addr_vpn4));
269 net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
272 net_vpn6_: VPN_RD net_ip6_
274 $$ = cfg_alloc(sizeof(net_addr_vpn6));
275 net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
278 net_roa4_: net_ip4_ MAX NUM AS NUM
280 $$ = cfg_alloc(sizeof(net_addr_roa4));
281 net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
282 if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
283 cf_error("Invalid max prefix length %u", $3);
286 net_roa6_: net_ip6_ MAX NUM AS NUM
288 $$ = cfg_alloc(sizeof(net_addr_roa6));
289 net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
290 if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
291 cf_error("Invalid max prefix length %u", $3);
296 $$ = cfg_alloc(sizeof(net_addr_roa6));
297 net_fill_mpls($$, $2);
300 net_ip_: net_ip4_ | net_ip6_ ;
301 net_vpn_: net_vpn4_ | net_vpn6_ ;
302 net_roa_: net_roa4_ | net_roa6_ ;
305 net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
314 /* Networks - regular */
319 if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP4))
320 cf_error("IPv4 network constant expected");
321 $$ = * SYM_VAL($1).net;
328 if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
329 cf_error("IPv6 network constant expected");
330 $$ = * SYM_VAL($1).net;
337 if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
338 cf_error("IP network constant expected");
339 $$ = * SYM_VAL($1).net;
346 if ($1->class != (SYM_CONSTANT | T_NET))
347 cf_error("Network constant expected");
348 $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
355 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
356 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
358 if ($1->class == (SYM_CONSTANT | T_IP))
359 net_fill_ip_host(&($$), SYM_VAL($1).ip);
360 else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
361 $$ = * SYM_VAL($1).net;
363 cf_error("IP address or network constant expected");
367 label_stack_start: NUM
369 $$ = cfg_allocz(sizeof(mpls_label_stack));
376 | label_stack '/' NUM {
377 if ($1->len >= MPLS_MAX_LABEL_STACK)
378 cf_error("Too many labels in stack");
379 $1->stack[$1->len++] = $3;
386 $$ = tm_parse_time($1);
388 cf_error("Invalid date/time");
395 if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
402 | /* empty */ { $$ = NULL; }
406 TEXT { $$.type = T_STRING; $$.val.s = $1; }
407 | IP4 { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
408 | IP6 { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
410 if (($1->class == (SYM_CONSTANT | T_STRING)) ||
411 ($1->class == (SYM_CONSTANT | T_IP)))
414 cf_error("String or IP constant expected");
417 $$ = cf_eval($2, T_VOID);
418 if (($$.type != T_BYTESTRING) && ($$.type != T_STRING))
419 cf_error("Bytestring or string value expected");
425 | bytestring_expr { $$ = cf_eval($1, T_BYTESTRING).val.bs; }
429 BYTETEXT { $$.type = T_BYTESTRING; $$.val.bs = $1; }
430 | TEXT { $$.type = T_STRING; $$.val.s = $1; }
432 $$ = cf_eval($1, T_VOID);
433 if (($$.type != T_BYTESTRING) && ($$.type != T_STRING))
434 cf_error("Bytestring or string value expected");
441 | '(' term ')' { $$ = $2; }