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"
23 #include "filter/filter.h"
25 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
33 cf_error("Value %u out of range (0-65535)", val);
36 #define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
37 static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
39 case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break;
40 case SYM_TEMPLATE: cf_assert(sym->class == SYM_TEMPLATE, "Protocol template name required"); break;
41 case SYM_FUNCTION: cf_assert(sym->class == SYM_FUNCTION, "Function name required"); break;
42 case SYM_FILTER: cf_assert(sym->class == SYM_FILTER, "Filter name required"); break;
43 case SYM_TABLE: cf_assert(sym->class == SYM_TABLE, "Table name required"); break;
44 case SYM_ATTRIBUTE: cf_assert(sym->class == SYM_ATTRIBUTE, "Custom attribute name required"); break;
45 case SYM_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break;
46 case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break;
47 default: bug("This shall not happen");
64 struct rtable_config *r;
65 struct channel_config *cc;
68 enum filter_return fret;
70 struct f_dynamic_attr fda;
71 struct f_static_attr fsa;
74 const struct filter *f;
78 struct password_item *p;
79 struct rt_show_data *ra;
80 struct sym_show_data *sd;
81 struct lsadb_show_data *ld;
82 struct mrt_dump_data *md;
88 struct channel_limit cl;
89 struct timeformat *tf;
90 mpls_label_stack *mls;
93 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
94 %token GEQ LEQ NEQ AND OR
100 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
102 %type <iface> ipa_scope
104 %type <i> expr bool pxlen4
105 %type <time> expr_us time
107 %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
108 %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
109 %type <mls> label_stack_start label_stack
110 %type <s> CF_SYM_VOID
112 %type <t> text opttext
115 %nonassoc PREFIX_DUMMY
117 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
125 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
129 /* Basic config file structure */
131 config: conf_entries END { return 0; }
132 | CLI_MARKER cli_cmd { return 0; }
143 /* Constant expressions */
148 DEFINE CF_SYM_VOID '=' term ';' {
149 struct f_val *val = cfg_alloc(sizeof(struct f_val));
150 if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
151 cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
157 | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
159 if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
160 $$ = SYM_VAL($1).i; }
164 expr S { $$ = $1 S_; }
165 | expr MS { $$ = $1 MS_; }
166 | expr US { $$ = $1 US_; }
169 CF_SYM_VOID: CF_SYM_UNDEFINED ;
171 symbol: CF_SYM_VOID | CF_SYM_KNOWN ;
181 | /* Silence means agreement */ { $$ = 1; }
188 IP4 { $$ = ipa_from_ip4($1); }
189 | IP6 { $$ = ipa_from_ip6($1); }
191 if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
197 /* empty */ { $$ = NULL; }
198 | '%' symbol { $$ = if_get_by_name($2->name); }
202 /* Networks - internal */
206 if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
213 net_fill_ip4(&($$), $1, $2);
215 net_addr_ip4 *n = (void *) &($$);
216 if (!net_validate_ip4(n))
217 cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
218 n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
221 net_ip6_: IP6 '/' NUM
223 if ($3 > IP6_MAX_PREFIX_LENGTH)
224 cf_error("Invalid prefix length %u", $3);
226 net_fill_ip6(&($$), $1, $3);
228 net_addr_ip6 *n = (void *) &($$);
229 if (!net_validate_ip6(n))
230 cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
231 n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
234 net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
236 if ($3 > IP6_MAX_PREFIX_LENGTH)
237 cf_error("Invalid prefix length %u", $3);
239 if ($7 > IP6_MAX_PREFIX_LENGTH)
240 cf_error("Invalid prefix length %u", $7);
242 $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
243 net_fill_ip6_sadr($$, $1, $3, $5, $7);
245 net_addr_ip6_sadr *n = (void *) $$;
246 if (!net_validate_ip6_sadr(n))
247 cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
248 n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
249 ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
250 ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
253 net_vpn4_: VPN_RD net_ip4_
255 $$ = cfg_alloc(sizeof(net_addr_vpn4));
256 net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
259 net_vpn6_: VPN_RD net_ip6_
261 $$ = cfg_alloc(sizeof(net_addr_vpn6));
262 net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
265 net_roa4_: net_ip4_ MAX NUM AS NUM
267 $$ = cfg_alloc(sizeof(net_addr_roa4));
268 net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
269 if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
270 cf_error("Invalid max prefix length %u", $3);
273 net_roa6_: net_ip6_ MAX NUM AS NUM
275 $$ = cfg_alloc(sizeof(net_addr_roa6));
276 net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
277 if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
278 cf_error("Invalid max prefix length %u", $3);
283 $$ = cfg_alloc(sizeof(net_addr_roa6));
284 net_fill_mpls($$, $2);
287 net_ip_: net_ip4_ | net_ip6_ ;
288 net_vpn_: net_vpn4_ | net_vpn6_ ;
289 net_roa_: net_roa4_ | net_roa6_ ;
292 net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
301 /* Networks - regular */
306 if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
307 cf_error("IPv6 network constant expected");
308 $$ = * SYM_VAL($1).net;
315 if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
316 cf_error("IP network constant expected");
317 $$ = * SYM_VAL($1).net;
324 if ($1->class != (SYM_CONSTANT | T_NET))
325 cf_error("Network constant expected");
326 $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
333 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
334 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
336 if ($1->class == (SYM_CONSTANT | T_IP))
337 net_fill_ip_host(&($$), SYM_VAL($1).ip);
338 else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
339 $$ = * SYM_VAL($1).net;
341 cf_error("IP address or network constant expected");
345 label_stack_start: NUM
347 $$ = cfg_allocz(sizeof(mpls_label_stack));
354 | label_stack '/' NUM {
355 if ($1->len >= MPLS_MAX_LABEL_STACK)
356 cf_error("Too many labels in stack");
357 $1->stack[$1->len++] = $3;
364 $$ = tm_parse_time($1);
366 cf_error("Invalid date/time");
373 if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
380 | /* empty */ { $$ = NULL; }