]> git.ipfire.org Git - thirdparty/bird.git/blob - conf/confbase.Y
Filter: Some people can't pronounce "postfixify" correctly. Let's try "linearize...
[thirdparty/bird.git] / conf / confbase.Y
1 /*
2 * BIRD -- Configuration Parser Top
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 CF_HDR
10
11 #define PARSER 1
12
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"
22 #include "nest/cli.h"
23 #include "filter/filter.h"
24
25 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
26
27 CF_DEFINES
28
29 static void
30 check_u16(uint val)
31 {
32 if (val > 0xFFFF)
33 cf_error("Value %u out of range (0-65535)", val);
34 }
35
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) {
38 switch (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");
48 }
49 }
50
51 CF_DECLS
52
53 %union {
54 uint i;
55 u32 i32;
56 u64 i64;
57 ip_addr a;
58 ip4_addr ip4;
59 ip6_addr ip6;
60 net_addr net;
61 net_addr *net_ptr;
62 struct symbol *s;
63 char *t;
64 struct rtable_config *r;
65 struct channel_config *cc;
66 struct f_inst *x;
67 struct f_inst *xp[2];
68 enum filter_return fret;
69 enum ec_subtype ecs;
70 struct f_dynamic_attr fda;
71 struct f_static_attr fsa;
72 struct f_lval flv;
73 struct f_line *fl;
74 const struct filter *f;
75 struct f_tree *e;
76 struct f_trie *trie;
77 struct f_val v;
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;
83 struct iface *iface;
84 void *g;
85 btime time;
86 struct f_prefix px;
87 struct proto_spec ps;
88 struct channel_limit cl;
89 struct timeformat *tf;
90 mpls_label_stack *mls;
91 }
92
93 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
94 %token GEQ LEQ NEQ AND OR
95 %token PO PC
96 %token <i> NUM ENUM
97 %token <ip4> IP4
98 %token <ip6> IP6
99 %token <i64> VPN_RD
100 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
101 %token <t> TEXT
102 %type <iface> ipa_scope
103
104 %type <i> expr bool pxlen4
105 %type <time> expr_us time
106 %type <a> ipa
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
111
112 %type <t> text opttext
113 %type <s> symbol
114
115 %nonassoc PREFIX_DUMMY
116 %left AND OR
117 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
118 %left '+' '-'
119 %left '*' '/' '%'
120 %left '!'
121 %nonassoc '.'
122
123 %start config
124
125 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
126
127 CF_GRAMMAR
128
129 /* Basic config file structure */
130
131 config: conf_entries END { return 0; }
132 | CLI_MARKER cli_cmd { return 0; }
133 ;
134
135 conf_entries:
136 /* EMPTY */
137 | conf_entries conf
138 ;
139
140 conf: ';' ;
141
142
143 /* Constant expressions */
144
145 conf: definition ;
146
147 definition:
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);
152 }
153 ;
154
155 expr:
156 NUM
157 | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
158 | CF_SYM_KNOWN {
159 if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
160 $$ = SYM_VAL($1).i; }
161 ;
162
163 expr_us:
164 expr S { $$ = $1 S_; }
165 | expr MS { $$ = $1 MS_; }
166 | expr US { $$ = $1 US_; }
167 ;
168
169 CF_SYM_VOID: CF_SYM_UNDEFINED ;
170
171 symbol: CF_SYM_VOID | CF_SYM_KNOWN ;
172
173 /* Switches */
174
175 bool:
176 expr { $$ = !!$1; }
177 | ON { $$ = 1; }
178 | YES { $$ = 1; }
179 | OFF { $$ = 0; }
180 | NO { $$ = 0; }
181 | /* Silence means agreement */ { $$ = 1; }
182 ;
183
184
185 /* Addresses */
186
187 ipa:
188 IP4 { $$ = ipa_from_ip4($1); }
189 | IP6 { $$ = ipa_from_ip6($1); }
190 | CF_SYM_KNOWN {
191 if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
192 $$ = SYM_VAL($1).ip;
193 }
194 ;
195
196 ipa_scope:
197 /* empty */ { $$ = NULL; }
198 | '%' symbol { $$ = if_get_by_name($2->name); }
199 ;
200
201
202 /* Networks - internal */
203
204 pxlen4:
205 '/' NUM {
206 if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
207 $$ = $2;
208 }
209 ;
210
211 net_ip4_: IP4 pxlen4
212 {
213 net_fill_ip4(&($$), $1, $2);
214
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);
219 };
220
221 net_ip6_: IP6 '/' NUM
222 {
223 if ($3 > IP6_MAX_PREFIX_LENGTH)
224 cf_error("Invalid prefix length %u", $3);
225
226 net_fill_ip6(&($$), $1, $3);
227
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);
232 };
233
234 net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
235 {
236 if ($3 > IP6_MAX_PREFIX_LENGTH)
237 cf_error("Invalid prefix length %u", $3);
238
239 if ($7 > IP6_MAX_PREFIX_LENGTH)
240 cf_error("Invalid prefix length %u", $7);
241
242 $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
243 net_fill_ip6_sadr($$, $1, $3, $5, $7);
244
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);
251 };
252
253 net_vpn4_: VPN_RD net_ip4_
254 {
255 $$ = cfg_alloc(sizeof(net_addr_vpn4));
256 net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
257 }
258
259 net_vpn6_: VPN_RD net_ip6_
260 {
261 $$ = cfg_alloc(sizeof(net_addr_vpn6));
262 net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
263 }
264
265 net_roa4_: net_ip4_ MAX NUM AS NUM
266 {
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);
271 };
272
273 net_roa6_: net_ip6_ MAX NUM AS NUM
274 {
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);
279 };
280
281 net_mpls_: MPLS NUM
282 {
283 $$ = cfg_alloc(sizeof(net_addr_roa6));
284 net_fill_mpls($$, $2);
285 }
286
287 net_ip_: net_ip4_ | net_ip6_ ;
288 net_vpn_: net_vpn4_ | net_vpn6_ ;
289 net_roa_: net_roa4_ | net_roa6_ ;
290
291 net_:
292 net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
293 | net_vpn_
294 | net_roa_
295 | net_flow_
296 | net_ip6_sadr_
297 | net_mpls_
298 ;
299
300
301 /* Networks - regular */
302
303 net_ip6:
304 net_ip6_
305 | CF_SYM_KNOWN {
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;
309 }
310 ;
311
312 net_ip:
313 net_ip_
314 | CF_SYM_KNOWN {
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;
318 }
319 ;
320
321 net_any:
322 net_
323 | CF_SYM_KNOWN {
324 if ($1->class != (SYM_CONSTANT | T_NET))
325 cf_error("Network constant expected");
326 $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
327 }
328 ;
329
330 net_or_ipa:
331 net_ip4_
332 | net_ip6_
333 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
334 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
335 | CF_SYM_KNOWN {
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;
340 else
341 cf_error("IP address or network constant expected");
342 }
343 ;
344
345 label_stack_start: NUM
346 {
347 $$ = cfg_allocz(sizeof(mpls_label_stack));
348 $$->len = 1;
349 $$->stack[0] = $1;
350 };
351
352 label_stack:
353 label_stack_start
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;
358 $$ = $1;
359 }
360 ;
361
362 time:
363 TEXT {
364 $$ = tm_parse_time($1);
365 if (!$$)
366 cf_error("Invalid date/time");
367 }
368 ;
369
370 text:
371 TEXT
372 | CF_SYM_KNOWN {
373 if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
374 $$ = SYM_VAL($1).s;
375 }
376 ;
377
378 opttext:
379 TEXT
380 | /* empty */ { $$ = NULL; }
381 ;
382
383
384 CF_CODE
385
386 CF_END