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/bfd.h"
23 #include "nest/cli.h"
24 #include "filter/filter.h"
25
26 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
27
28 CF_DEFINES
29
30 static void
check_u16(uint val)31 check_u16(uint val)
32 {
33 if (val > 0xFFFF)
34 cf_error("Value %u out of range (0-65535)", val);
35 }
36
37 #define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
cf_assert_symbol(const struct symbol * sym,uint class)38 static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
39 switch (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_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break;
47 case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break;
48 default: bug("This shall not happen");
49 }
50 }
51
52 CF_DECLS
53
54 %union {
55 uint i;
56 u32 i32;
57 u64 i64;
58 ip_addr a;
59 ip4_addr ip4;
60 ip6_addr ip6;
61 net_addr net;
62 net_addr *net_ptr;
63 struct symbol *s;
64 const char *t;
65 struct rtable_config *r;
66 struct channel_config *cc;
67 struct channel *c;
68 struct f_inst *x;
69 struct {
70 struct f_inst *begin, *end;
71 } xp;
72 enum filter_return fret;
73 enum ec_subtype ecs;
74 struct f_dynamic_attr fda;
75 struct f_static_attr fsa;
76 struct f_lval flv;
77 struct f_line *fl;
78 const struct filter *f;
79 struct f_tree *e;
80 struct f_trie *trie;
81 struct f_val v;
82 struct password_item *p;
83 struct rt_show_data *ra;
84 struct sym_show_data *sd;
85 struct lsadb_show_data *ld;
86 struct mrt_dump_data *md;
87 struct iface *iface;
88 void *g;
89 btime time;
90 struct f_prefix px;
91 struct proto_spec ps;
92 struct channel_limit cl;
93 struct timeformat *tf;
94 mpls_label_stack *mls;
95 }
96
97 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
98 %token GEQ LEQ NEQ AND OR
99 %token PO PC
100 %token <i> NUM ENUM
101 %token <ip4> IP4
102 %token <ip6> IP6
103 %token <i64> VPN_RD
104 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
105 %token <t> TEXT
106 %type <iface> ipa_scope
107
108 %type <i> expr bool pxlen4
109 %type <time> expr_us time
110 %type <a> ipa
111 %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
112 %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
113 %type <mls> label_stack_start label_stack
114
115 %type <t> text opttext
116 %type <s> symbol
117
118 %nonassoc PREFIX_DUMMY
119 %left AND OR
120 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
121 %left '+' '-'
122 %left '*' '/' '%'
123 %left '!'
124 %nonassoc '.'
125
126 %start config
127
128 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
129
130 CF_GRAMMAR
131
132 /* Basic config file structure */
133
134 config: conf_entries END { return 0; }
135 | CLI_MARKER cli_cmd { return 0; }
136 ;
137
138 conf_entries:
139 /* EMPTY */
140 | conf_entries conf
141 ;
142
143 conf: ';' ;
144
145
146 /* Constant expressions */
147
148 conf: definition ;
149
150 definition:
151 DEFINE symbol '=' term ';' {
152 struct f_val *val = cfg_allocz(sizeof(struct f_val));
153 if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
154 cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
155 }
156 ;
157
158 expr:
159 NUM
160 | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
161 | CF_SYM_KNOWN {
162 if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
163 $$ = SYM_VAL($1).i; }
164 ;
165
166 expr_us:
167 expr S { $$ = $1 S_; }
168 | expr MS { $$ = $1 MS_; }
169 | expr US { $$ = $1 US_; }
170 ;
171
172 symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ;
173
174 /* Switches */
175
176 bool:
177 expr { $$ = !!$1; }
178 | ON { $$ = 1; }
179 | YES { $$ = 1; }
180 | OFF { $$ = 0; }
181 | NO { $$ = 0; }
182 | /* Silence means agreement */ { $$ = 1; }
183 ;
184
185
186 /* Addresses */
187
188 ipa:
189 IP4 { $$ = ipa_from_ip4($1); }
190 | IP6 { $$ = ipa_from_ip6($1); }
191 | CF_SYM_KNOWN {
192 if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
193 $$ = SYM_VAL($1).ip;
194 }
195 ;
196
197 ipa_scope:
198 /* empty */ { $$ = NULL; }
199 | '%' symbol { $$ = if_get_by_name($2->name); }
200 ;
201
202
203 /* Networks - internal */
204
205 pxlen4:
206 '/' NUM {
207 if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
208 $$ = $2;
209 }
210 ;
211
212 net_ip4_: IP4 pxlen4
213 {
214 net_fill_ip4(&($$), $1, $2);
215
216 net_addr_ip4 *n = (void *) &($$);
217 if (!net_validate_ip4(n))
218 cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
219 n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
220 };
221
222 net_ip6_: IP6 '/' NUM
223 {
224 if ($3 > IP6_MAX_PREFIX_LENGTH)
225 cf_error("Invalid prefix length %u", $3);
226
227 net_fill_ip6(&($$), $1, $3);
228
229 net_addr_ip6 *n = (void *) &($$);
230 if (!net_validate_ip6(n))
231 cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
232 n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
233 };
234
235 net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
236 {
237 if ($3 > IP6_MAX_PREFIX_LENGTH)
238 cf_error("Invalid prefix length %u", $3);
239
240 if ($7 > IP6_MAX_PREFIX_LENGTH)
241 cf_error("Invalid prefix length %u", $7);
242
243 $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
244 net_fill_ip6_sadr($$, $1, $3, $5, $7);
245
246 net_addr_ip6_sadr *n = (void *) $$;
247 if (!net_validate_ip6_sadr(n))
248 cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
249 n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
250 ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
251 ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
252 };
253
254 net_vpn4_: VPN_RD net_ip4_
255 {
256 $$ = cfg_alloc(sizeof(net_addr_vpn4));
257 net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
258 }
259
260 net_vpn6_: VPN_RD net_ip6_
261 {
262 $$ = cfg_alloc(sizeof(net_addr_vpn6));
263 net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
264 }
265
266 net_roa4_: net_ip4_ MAX NUM AS NUM
267 {
268 $$ = cfg_alloc(sizeof(net_addr_roa4));
269 net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
270 if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
271 cf_error("Invalid max prefix length %u", $3);
272 };
273
274 net_roa6_: net_ip6_ MAX NUM AS NUM
275 {
276 $$ = cfg_alloc(sizeof(net_addr_roa6));
277 net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
278 if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
279 cf_error("Invalid max prefix length %u", $3);
280 };
281
282 net_mpls_: MPLS NUM
283 {
284 $$ = cfg_alloc(sizeof(net_addr_roa6));
285 net_fill_mpls($$, $2);
286 }
287
288 net_ip_: net_ip4_ | net_ip6_ ;
289 net_vpn_: net_vpn4_ | net_vpn6_ ;
290 net_roa_: net_roa4_ | net_roa6_ ;
291
292 net_:
293 net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
294 | net_vpn_
295 | net_roa_
296 | net_flow_
297 | net_ip6_sadr_
298 | net_mpls_
299 ;
300
301
302 /* Networks - regular */
303
304 net_ip6:
305 net_ip6_
306 | CF_SYM_KNOWN {
307 if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
308 cf_error("IPv6 network constant expected");
309 $$ = * SYM_VAL($1).net;
310 }
311 ;
312
313 net_ip:
314 net_ip_
315 | CF_SYM_KNOWN {
316 if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
317 cf_error("IP network constant expected");
318 $$ = * SYM_VAL($1).net;
319 }
320 ;
321
322 net_any:
323 net_
324 | CF_SYM_KNOWN {
325 if ($1->class != (SYM_CONSTANT | T_NET))
326 cf_error("Network constant expected");
327 $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
328 }
329 ;
330
331 net_or_ipa:
332 net_ip4_
333 | net_ip6_
334 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
335 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
336 | CF_SYM_KNOWN {
337 if ($1->class == (SYM_CONSTANT | T_IP))
338 net_fill_ip_host(&($$), SYM_VAL($1).ip);
339 else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
340 $$ = * SYM_VAL($1).net;
341 else
342 cf_error("IP address or network constant expected");
343 }
344 ;
345
346 label_stack_start: NUM
347 {
348 $$ = cfg_allocz(sizeof(mpls_label_stack));
349 $$->len = 1;
350 $$->stack[0] = $1;
351 };
352
353 label_stack:
354 label_stack_start
355 | label_stack '/' NUM {
356 if ($1->len >= MPLS_MAX_LABEL_STACK)
357 cf_error("Too many labels in stack");
358 $1->stack[$1->len++] = $3;
359 $$ = $1;
360 }
361 ;
362
363 time:
364 TEXT {
365 $$ = tm_parse_time($1);
366 if (!$$)
367 cf_error("Invalid date/time");
368 }
369 ;
370
371 text:
372 TEXT
373 | CF_SYM_KNOWN {
374 if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
375 $$ = SYM_VAL($1).s;
376 }
377 ;
378
379 opttext:
380 TEXT
381 | /* empty */ { $$ = NULL; }
382 ;
383
384
385 CF_CODE
386
387 CF_END
388