]>
Commit | Line | Data |
---|---|---|
b9d70dc8 PM |
1 | /* |
2 | * BIRD - filters | |
3 | * | |
1c20608e | 4 | * Copyright 1998--2000 Pavel Machek |
b9d70dc8 PM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
c9f8c1a8 | 7 | * |
1877dab2 | 8 | FIXME: priority of ! should be lower |
b9d70dc8 PM |
9 | */ |
10 | ||
11 | CF_HDR | |
12 | ||
2edb31b0 MM |
13 | CF_DEFINES |
14 | ||
b8cc390e OZ |
15 | static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } |
16 | static inline u32 pair_a(u32 p) { return p >> 16; } | |
17 | static inline u32 pair_b(u32 p) { return p & 0xFFFF; } | |
18 | ||
19 | ||
20 | /* | |
21 | * Sets and their items are during parsing handled as lists, linked | |
22 | * through left ptr. The first item in a list also contains a pointer | |
23 | * to the last item in a list (right ptr). For convenience, even items | |
24 | * are handled as one-item lists. Lists are merged by f_merge_items(). | |
25 | */ | |
b2f00837 OZ |
26 | static int |
27 | f_valid_set_type(int type) | |
28 | { | |
29 | switch (type) | |
30 | { | |
31 | case T_INT: | |
32 | case T_PAIR: | |
33 | case T_QUAD: | |
34 | case T_ENUM: | |
35 | case T_IP: | |
36 | case T_EC: | |
66dbdbd9 | 37 | case T_LC: |
83715aa8 | 38 | case T_RD: |
b2f00837 OZ |
39 | return 1; |
40 | ||
41 | default: | |
42 | return 0; | |
43 | } | |
44 | } | |
b8cc390e OZ |
45 | |
46 | static inline struct f_tree * | |
47 | f_new_item(struct f_val from, struct f_val to) | |
92a72a4c | 48 | { |
b8cc390e OZ |
49 | struct f_tree *t = f_new_tree(); |
50 | t->right = t; | |
51 | t->from = from; | |
52 | t->to = to; | |
53 | return t; | |
54 | } | |
92a72a4c | 55 | |
b8cc390e OZ |
56 | static inline struct f_tree * |
57 | f_merge_items(struct f_tree *a, struct f_tree *b) | |
58 | { | |
59 | if (!a) return b; | |
60 | a->right->left = b; | |
61 | a->right = b->right; | |
62 | b->right = NULL; | |
63 | return a; | |
64 | } | |
92a72a4c | 65 | |
b8cc390e OZ |
66 | static inline struct f_tree * |
67 | f_new_pair_item(int fa, int ta, int fb, int tb) | |
68 | { | |
60566c5c OZ |
69 | check_u16(fa); |
70 | check_u16(ta); | |
71 | check_u16(fb); | |
72 | check_u16(tb); | |
73 | ||
74 | if ((ta < fa) || (tb < fb)) | |
75 | cf_error( "From value cannot be higher that To value in pair sets"); | |
76 | ||
b8cc390e OZ |
77 | struct f_tree *t = f_new_tree(); |
78 | t->right = t; | |
79 | t->from.type = t->to.type = T_PAIR; | |
80 | t->from.val.i = pair(fa, fb); | |
81 | t->to.val.i = pair(ta, tb); | |
82 | return t; | |
92a72a4c OZ |
83 | } |
84 | ||
b8cc390e OZ |
85 | static inline struct f_tree * |
86 | f_new_pair_set(int fa, int ta, int fb, int tb) | |
4fc36f39 | 87 | { |
60566c5c OZ |
88 | check_u16(fa); |
89 | check_u16(ta); | |
90 | check_u16(fb); | |
91 | check_u16(tb); | |
c454872f | 92 | |
b8cc390e OZ |
93 | if ((ta < fa) || (tb < fb)) |
94 | cf_error( "From value cannot be higher that To value in pair sets"); | |
c454872f | 95 | |
60566c5c OZ |
96 | struct f_tree *lst = NULL; |
97 | int i; | |
98 | ||
b8cc390e OZ |
99 | for (i = fa; i <= ta; i++) |
100 | lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb)); | |
101 | ||
102 | return lst; | |
4fc36f39 OF |
103 | } |
104 | ||
60566c5c | 105 | #define CC_ALL 0xFFFF |
42a0c054 | 106 | #define EC_ALL 0xFFFFFFFF |
60566c5c | 107 | #define LC_ALL 0xFFFFFFFF |
42a0c054 OZ |
108 | |
109 | static struct f_tree * | |
110 | f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) | |
111 | { | |
112 | u64 fm, to; | |
113 | ||
e46128fb | 114 | if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) { |
42a0c054 OZ |
115 | check_u16(vf); |
116 | if (vt == EC_ALL) | |
117 | vt = 0xFFFF; | |
118 | else | |
119 | check_u16(vt); | |
120 | } | |
121 | ||
122 | if (kind == EC_GENERIC) { | |
123 | fm = ec_generic(key, vf); | |
124 | to = ec_generic(key, vt); | |
125 | } | |
126 | else if (ipv4_used) { | |
127 | fm = ec_ip4(kind, key, vf); | |
128 | to = ec_ip4(kind, key, vt); | |
129 | } | |
130 | else if (key < 0x10000) { | |
131 | fm = ec_as2(kind, key, vf); | |
132 | to = ec_as2(kind, key, vt); | |
133 | } | |
134 | else { | |
135 | fm = ec_as4(kind, key, vf); | |
136 | to = ec_as4(kind, key, vt); | |
137 | } | |
138 | ||
139 | struct f_tree *t = f_new_tree(); | |
140 | t->right = t; | |
141 | t->from.type = t->to.type = T_EC; | |
142 | t->from.val.ec = fm; | |
143 | t->to.val.ec = to; | |
144 | return t; | |
145 | } | |
146 | ||
60566c5c OZ |
147 | static struct f_tree * |
148 | f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) | |
149 | { | |
150 | struct f_tree *t = f_new_tree(); | |
151 | t->right = t; | |
152 | t->from.type = t->to.type = T_LC; | |
153 | t->from.val.lc = (lcomm) {f1, f2, f3}; | |
154 | t->to.val.lc = (lcomm) {t1, t2, t3}; | |
155 | return t; | |
156 | } | |
157 | ||
42a0c054 | 158 | static inline struct f_inst * |
5a14df39 | 159 | f_generate_empty(struct f_dynamic_attr dyn) |
5e173e9f | 160 | { |
5a14df39 | 161 | struct f_inst *e = f_new_inst(FI_EMPTY); |
42a0c054 | 162 | |
5a14df39 | 163 | switch (dyn.type & EAF_TYPE_MASK) { |
42a0c054 OZ |
164 | case EAF_TYPE_AS_PATH: |
165 | e->aux = T_PATH; | |
166 | break; | |
167 | case EAF_TYPE_INT_SET: | |
168 | e->aux = T_CLIST; | |
169 | break; | |
170 | case EAF_TYPE_EC_SET: | |
171 | e->aux = T_ECLIST; | |
172 | break; | |
66dbdbd9 OZ |
173 | case EAF_TYPE_LC_SET: |
174 | e->aux = T_LCLIST; | |
175 | break; | |
42a0c054 OZ |
176 | default: |
177 | cf_error("Can't empty that attribute"); | |
178 | } | |
179 | ||
5a14df39 | 180 | struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn); |
7f0ac737 | 181 | s->a[0].p = e; |
5a14df39 | 182 | return s; |
42a0c054 OZ |
183 | } |
184 | ||
185 | ||
186 | static inline struct f_inst * | |
187 | f_generate_dpair(struct f_inst *t1, struct f_inst *t2) | |
188 | { | |
189 | struct f_inst *rv; | |
190 | ||
5a14df39 | 191 | if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) { |
42a0c054 OZ |
192 | if ((t1->aux != T_INT) || (t2->aux != T_INT)) |
193 | cf_error( "Can't operate with value of non-integer type in pair constructor"); | |
194 | ||
7f0ac737 MM |
195 | check_u16(t1->a[1].i); |
196 | check_u16(t2->a[1].i); | |
42a0c054 | 197 | |
5a14df39 | 198 | rv = f_new_inst(FI_CONSTANT); |
42a0c054 | 199 | rv->aux = T_PAIR; |
7f0ac737 | 200 | rv->a[1].i = pair(t1->a[1].i, t2->a[1].i); |
42a0c054 OZ |
201 | } |
202 | else { | |
5a14df39 | 203 | rv = f_new_inst(FI_PAIR_CONSTRUCT); |
7f0ac737 MM |
204 | rv->a[0].p = t1; |
205 | rv->a[1].p = t2; | |
42a0c054 OZ |
206 | } |
207 | ||
208 | return rv; | |
209 | } | |
210 | ||
211 | static inline struct f_inst * | |
212 | f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) | |
213 | { | |
214 | struct f_inst *rv; | |
215 | int c1 = 0, c2 = 0, ipv4_used = 0; | |
216 | u32 key = 0, val2 = 0; | |
217 | ||
5a14df39 | 218 | if (tk->fi_code == FI_CONSTANT) { |
42a0c054 OZ |
219 | c1 = 1; |
220 | ||
221 | if (tk->aux == T_INT) { | |
7f0ac737 | 222 | ipv4_used = 0; key = tk->a[1].i; |
42a0c054 OZ |
223 | } |
224 | else if (tk->aux == T_QUAD) { | |
7f0ac737 | 225 | ipv4_used = 1; key = tk->a[1].i; |
42a0c054 OZ |
226 | } |
227 | else | |
228 | cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); | |
229 | } | |
230 | ||
42a0c054 | 231 | /* IP->Quad implicit conversion */ |
5a14df39 | 232 | else if (tk->fi_code == FI_CONSTANT_INDIRECT) { |
42a0c054 | 233 | c1 = 1; |
7f0ac737 | 234 | struct f_val *val = tk->a[0].p; |
1103b32e OZ |
235 | |
236 | if (val->type == T_INT) { | |
237 | ipv4_used = 0; key = val->val.i; | |
238 | } | |
239 | else if (val->type == T_QUAD) { | |
240 | ipv4_used = 1; key = val->val.i; | |
241 | } | |
5e173e9f JMM |
242 | else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) { |
243 | ipv4_used = 1; key = ipa_to_u32(val->val.ip); | |
42a0c054 OZ |
244 | } |
245 | else | |
246 | cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); | |
247 | } | |
42a0c054 | 248 | |
5a14df39 | 249 | if (tv->fi_code == FI_CONSTANT) { |
42a0c054 OZ |
250 | if (tv->aux != T_INT) |
251 | cf_error("Can't operate with value of non-integer type in EC constructor"); | |
252 | c2 = 1; | |
7f0ac737 | 253 | val2 = tv->a[1].i; |
42a0c054 OZ |
254 | } |
255 | ||
256 | if (c1 && c2) { | |
257 | u64 ec; | |
5e173e9f | 258 | |
42a0c054 OZ |
259 | if (kind == EC_GENERIC) { |
260 | ec = ec_generic(key, val2); | |
261 | } | |
262 | else if (ipv4_used) { | |
263 | check_u16(val2); | |
264 | ec = ec_ip4(kind, key, val2); | |
265 | } | |
266 | else if (key < 0x10000) { | |
267 | ec = ec_as2(kind, key, val2); | |
268 | } | |
269 | else { | |
270 | check_u16(val2); | |
271 | ec = ec_as4(kind, key, val2); | |
272 | } | |
273 | ||
274 | NEW_F_VAL; | |
5a14df39 | 275 | rv = f_new_inst(FI_CONSTANT_INDIRECT); |
7f0ac737 | 276 | rv->a[0].p = val; |
42a0c054 OZ |
277 | val->type = T_EC; |
278 | val->val.ec = ec; | |
279 | } | |
280 | else { | |
5a14df39 | 281 | rv = f_new_inst(FI_EC_CONSTRUCT); |
42a0c054 | 282 | rv->aux = kind; |
7f0ac737 MM |
283 | rv->a[0].p = tk; |
284 | rv->a[1].p = tv; | |
42a0c054 OZ |
285 | } |
286 | ||
287 | return rv; | |
78e33c29 | 288 | } |
42a0c054 | 289 | |
66dbdbd9 OZ |
290 | static inline struct f_inst * |
291 | f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) | |
292 | { | |
293 | struct f_inst *rv; | |
294 | ||
5a14df39 | 295 | if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) { |
66dbdbd9 OZ |
296 | if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) |
297 | cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); | |
298 | ||
5a14df39 | 299 | rv = f_new_inst(FI_CONSTANT_INDIRECT); |
66dbdbd9 OZ |
300 | |
301 | NEW_F_VAL; | |
7f0ac737 | 302 | rv->a[0].p = val; |
66dbdbd9 | 303 | val->type = T_LC; |
7f0ac737 | 304 | val->val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i }; |
66dbdbd9 OZ |
305 | } |
306 | else | |
307 | { | |
478f9bab | 308 | rv = f_new_inst(FI_LC_CONSTRUCT); |
7f0ac737 MM |
309 | rv->a[0].p = t1; |
310 | rv->a[1].p = t2; | |
311 | rv->a[2].p = t3; | |
66dbdbd9 OZ |
312 | } |
313 | ||
314 | return rv; | |
315 | } | |
316 | ||
e8bc64e3 JMM |
317 | static inline struct f_inst * |
318 | f_generate_path_mask(struct f_path_mask *t) | |
319 | { | |
320 | for (struct f_path_mask *tt = t; tt; tt = tt->next) { | |
321 | if (tt->kind == PM_ASN_EXPR) { | |
322 | struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT); | |
7f0ac737 | 323 | mrv->a[0].p = t; |
e8bc64e3 JMM |
324 | return mrv; |
325 | } | |
326 | } | |
327 | ||
328 | NEW_F_VAL; | |
329 | val->type = T_PATH_MASK; | |
330 | val->val.path_mask = t; | |
331 | ||
332 | struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT); | |
7f0ac737 | 333 | rv->a[0].p = val; |
e8bc64e3 JMM |
334 | |
335 | return rv; | |
336 | } | |
42a0c054 | 337 | |
9b0a0ba9 OZ |
338 | /* |
339 | * Remove all new lines and doubled whitespaces | |
340 | * and convert all tabulators to spaces | |
341 | * and return a copy of string | |
342 | */ | |
343 | char * | |
344 | assert_copy_expr(const char *start, size_t len) | |
345 | { | |
346 | /* XXX: Allocates maybe a little more memory than we really finally need */ | |
347 | char *str = cfg_alloc(len + 1); | |
348 | ||
349 | char *dst = str; | |
350 | const char *src = start - 1; | |
351 | const char *end = start + len; | |
352 | while (++src < end) | |
353 | { | |
354 | if (*src == '\n') | |
355 | continue; | |
356 | ||
357 | /* Skip doubled whitespaces */ | |
358 | if (src != start) | |
359 | { | |
360 | const char *prev = src - 1; | |
361 | if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t')) | |
362 | continue; | |
363 | } | |
364 | ||
365 | if (*src == '\t') | |
366 | *dst = ' '; | |
367 | else | |
368 | *dst = *src; | |
369 | ||
370 | dst++; | |
371 | } | |
372 | *dst = '\0'; | |
373 | ||
374 | return str; | |
375 | } | |
376 | ||
377 | /* | |
378 | * assert_done - create f_instruction of bt_assert | |
379 | * @expr: expression in bt_assert() | |
380 | * @start: pointer to first char of test expression | |
381 | * @end: pointer to the last char of test expression | |
382 | */ | |
383 | static struct f_inst * | |
384 | assert_done(struct f_inst *expr, const char *start, const char *end) | |
385 | { | |
386 | struct f_inst *i; | |
d1ba927b | 387 | i = f_new_inst(FI_ASSERT); |
7f0ac737 | 388 | i->a[0].p = expr; |
9b0a0ba9 OZ |
389 | |
390 | if (end >= start) | |
391 | { | |
7f0ac737 | 392 | i->a[1].p = assert_copy_expr(start, end - start + 1); |
9b0a0ba9 OZ |
393 | } |
394 | else | |
395 | { | |
396 | /* this is a break of lexer buffer */ | |
7f0ac737 | 397 | i->a[1].p = "???"; |
9b0a0ba9 | 398 | } |
42a0c054 | 399 | |
9b0a0ba9 OZ |
400 | return i; |
401 | } | |
42a0c054 | 402 | |
b9d70dc8 PM |
403 | CF_DECLS |
404 | ||
e4a73dbf | 405 | CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, |
ba921648 | 406 | ACCEPT, REJECT, ERROR, QUITBIRD, |
8c9986d3 | 407 | INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC, |
66dbdbd9 | 408 | SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, |
7db7b7db | 409 | IF, THEN, ELSE, CASE, |
42a0c054 | 410 | TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, |
5b208e29 | 411 | FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, |
a5fc5958 | 412 | PREFERENCE, |
b24b7811 | 413 | ROA_CHECK, ASN, SRC, |
61e501da | 414 | IS_V4, IS_V6, |
e58f8c28 | 415 | LEN, MAXLEN, |
f4536657 | 416 | DEFINED, |
7f77e250 | 417 | ADD, DELETE, CONTAINS, RESET, |
9c9cc35c | 418 | PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, |
afc54517 | 419 | EMPTY, |
265419a3 | 420 | FILTER, WHERE, EVAL, ATTRIBUTE, |
4b135d09 | 421 | BT_ASSERT, BT_TEST_SUITE, FORMAT) |
b9d70dc8 | 422 | |
f4536657 | 423 | %nonassoc THEN |
4ed8718a | 424 | %nonassoc ELSE |
f4536657 | 425 | |
5a14df39 MJM |
426 | %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr |
427 | %type <fda> dynamic_attr | |
428 | %type <fsa> static_attr | |
430da60f | 429 | %type <f> filter filter_body where_filter |
60566c5c OZ |
430 | %type <i> type break_command ec_kind |
431 | %type <i32> cnum | |
432 | %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body | |
b1a597e0 | 433 | %type <trie> fprefix_set |
5e173e9f JMM |
434 | %type <v> set_atom switch_atom fipa |
435 | %type <px> fprefix | |
436 | %type <s> decls declsn one_decl function_params | |
3e52d112 | 437 | %type <h> bgp_path bgp_path_tail |
9b0a0ba9 | 438 | %type <t> get_cf_position |
b9d70dc8 PM |
439 | |
440 | CF_GRAMMAR | |
441 | ||
f851f0d7 | 442 | conf: filter_def ; |
e0f2e42f | 443 | filter_def: |
b2b7bbfc OZ |
444 | FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } |
445 | filter_body { | |
446 | $2->def = $4; | |
ae3e1af2 | 447 | $4->name = $2->name; |
d4d75628 | 448 | DBG( "We have new filter defined (%s)\n", $2->name ); |
ae3e1af2 | 449 | cf_pop_scope(); |
b9d70dc8 PM |
450 | } |
451 | ; | |
452 | ||
f851f0d7 | 453 | conf: filter_eval ; |
1c20608e MM |
454 | filter_eval: |
455 | EVAL term { f_eval_int($2); } | |
456 | ; | |
457 | ||
265419a3 MM |
458 | conf: custom_attr ; |
459 | custom_attr: ATTRIBUTE type SYM ';' { | |
460 | cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda); | |
461 | }; | |
462 | ||
f851f0d7 | 463 | conf: bt_test_suite ; |
9b0a0ba9 OZ |
464 | bt_test_suite: |
465 | BT_TEST_SUITE '(' SYM ',' text ')' { | |
466 | if (!($3->class & SYM_FUNCTION)) | |
467 | cf_error("Function expected"); | |
468 | ||
469 | struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite)); | |
470 | t->fn = $3->def; | |
471 | t->fn_name = $3->name; | |
472 | t->dsc = $5; | |
473 | ||
474 | add_tail(&new_config->tests, &t->n); | |
475 | } | |
476 | ; | |
477 | ||
ba921648 PM |
478 | type: |
479 | INT { $$ = T_INT; } | |
480 | | BOOL { $$ = T_BOOL; } | |
481 | | IP { $$ = T_IP; } | |
8c9986d3 | 482 | | RD { $$ = T_RD; } |
5e173e9f | 483 | | PREFIX { $$ = T_NET; } |
ba921648 | 484 | | PAIR { $$ = T_PAIR; } |
126683fe | 485 | | QUAD { $$ = T_QUAD; } |
42a0c054 | 486 | | EC { $$ = T_EC; } |
66dbdbd9 | 487 | | LC { $$ = T_LC; } |
ba921648 | 488 | | STRING { $$ = T_STRING; } |
10a53608 PM |
489 | | BGPMASK { $$ = T_PATH_MASK; } |
490 | | BGPPATH { $$ = T_PATH; } | |
491 | | CLIST { $$ = T_CLIST; } | |
42a0c054 | 492 | | ECLIST { $$ = T_ECLIST; } |
66dbdbd9 | 493 | | LCLIST { $$ = T_LCLIST; } |
c8cafc8e | 494 | | type SET { |
ba921648 | 495 | switch ($1) { |
b1a597e0 | 496 | case T_INT: |
b1a597e0 | 497 | case T_PAIR: |
126683fe | 498 | case T_QUAD: |
42a0c054 | 499 | case T_EC: |
66dbdbd9 | 500 | case T_LC: |
83715aa8 | 501 | case T_RD: |
126683fe | 502 | case T_IP: |
b1a597e0 OZ |
503 | $$ = T_SET; |
504 | break; | |
505 | ||
5e173e9f | 506 | case T_NET: |
b1a597e0 OZ |
507 | $$ = T_PREFIX_SET; |
508 | break; | |
509 | ||
ba921648 | 510 | default: |
a5a947d4 | 511 | cf_error( "You can't create sets of this type." ); |
ba921648 | 512 | } |
b1a597e0 | 513 | } |
ba921648 PM |
514 | ; |
515 | ||
6dc7a0cb PM |
516 | one_decl: |
517 | type SYM { | |
4ee39ff2 OZ |
518 | struct f_val * val = cfg_alloc(sizeof(struct f_val)); |
519 | val->type = T_VOID; | |
083c43e2 | 520 | $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); |
d4d75628 | 521 | DBG( "New variable %s type %x\n", $2->name, $1 ); |
083c43e2 | 522 | $2->aux2 = NULL; |
6542ece9 | 523 | $$=$2; |
ba921648 PM |
524 | } |
525 | ; | |
526 | ||
6dc7a0cb PM |
527 | /* Decls with ';' at the end */ |
528 | decls: /* EMPTY */ { $$ = NULL; } | |
529 | | one_decl ';' decls { | |
530 | $$ = $1; | |
083c43e2 | 531 | $$->aux2 = $3; |
6dc7a0cb PM |
532 | } |
533 | ; | |
534 | ||
3c989eb4 | 535 | /* Declarations that have no ';' at the end. */ |
6dc7a0cb | 536 | declsn: one_decl { $$ = $1; } |
736fd730 | 537 | | one_decl ';' declsn { |
4515bdba | 538 | $$ = $1; |
083c43e2 | 539 | $$->aux2 = $3; |
6dc7a0cb PM |
540 | } |
541 | ; | |
542 | ||
e0f2e42f | 543 | filter_body: |
ba921648 | 544 | function_body { |
e0f2e42f MM |
545 | struct filter *f = cfg_alloc(sizeof(struct filter)); |
546 | f->name = NULL; | |
ba921648 | 547 | f->root = $1; |
e0f2e42f MM |
548 | $$ = f; |
549 | } | |
550 | ; | |
551 | ||
552 | filter: | |
553 | SYM { | |
a5a947d4 | 554 | if ($1->class != SYM_FILTER) cf_error("No such filter."); |
e0f2e42f MM |
555 | $$ = $1->def; |
556 | } | |
557 | | filter_body | |
558 | ; | |
559 | ||
430da60f MM |
560 | where_filter: |
561 | WHERE term { | |
224b77d4 | 562 | /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ |
430da60f MM |
563 | struct filter *f = cfg_alloc(sizeof(struct filter)); |
564 | struct f_inst *i, *acc, *rej; | |
5a14df39 | 565 | acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ |
7f0ac737 MM |
566 | acc->a[0].p = NULL; |
567 | acc->a[1].i = F_ACCEPT; | |
5a14df39 | 568 | rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */ |
7f0ac737 MM |
569 | rej->a[0].p = NULL; |
570 | rej->a[1].i = F_REJECT; | |
5a14df39 | 571 | i = f_new_inst(FI_CONDITION); /* IF */ |
7f0ac737 MM |
572 | i->a[0].p = $2; |
573 | i->a[1].p = acc; | |
574 | i->a[2].p = rej; | |
430da60f MM |
575 | f->name = NULL; |
576 | f->root = i; | |
577 | $$ = f; | |
578 | } | |
579 | ; | |
580 | ||
ba921648 | 581 | function_params: |
d4d75628 | 582 | '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } |
6dc7a0cb | 583 | | '(' ')' { $$=NULL; } |
ba921648 | 584 | ; |
b9d70dc8 | 585 | |
ba921648 PM |
586 | function_body: |
587 | decls '{' cmds '}' { | |
aa461248 OZ |
588 | if ($1) { |
589 | /* Prepend instruction to clear local variables */ | |
5a14df39 | 590 | $$ = f_new_inst(FI_CLEAR_LOCAL_VARS); |
7f0ac737 | 591 | $$->a[0].p = $1; |
aa461248 OZ |
592 | $$->next = $3; |
593 | } else | |
594 | $$ = $3; | |
84c7e194 | 595 | } |
ba921648 PM |
596 | ; |
597 | ||
f851f0d7 | 598 | conf: function_def ; |
ba921648 | 599 | function_def: |
bf3eb98e MM |
600 | FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); |
601 | $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); | |
602 | cf_push_scope($2); | |
603 | } function_params function_body { | |
604 | $2->def = $5; | |
083c43e2 | 605 | $2->aux2 = $4; |
c8cafc8e | 606 | DBG("Hmm, we've got one function here - %s\n", $2->name); |
ae3e1af2 | 607 | cf_pop_scope(); |
ba921648 PM |
608 | } |
609 | ; | |
610 | ||
611 | /* Programs */ | |
612 | ||
5f47c4c1 OZ |
613 | /* Hack: $$ of cmds_int is the last node. |
614 | $$->next of cmds_int is temporary used for the first node */ | |
615 | ||
ba921648 | 616 | cmds: /* EMPTY */ { $$ = NULL; } |
5f47c4c1 OZ |
617 | | cmds_int { $$ = $1->next; $1->next = NULL; } |
618 | ; | |
619 | ||
620 | cmds_int: cmd { $$ = $1; $1->next = $1; } | |
621 | | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; } | |
84c7e194 PM |
622 | ; |
623 | ||
2575593e | 624 | block: |
ba921648 | 625 | cmd { |
2575593e PM |
626 | $$=$1; |
627 | } | |
628 | | '{' cmds '}' { | |
629 | $$=$2; | |
630 | } | |
631 | ; | |
632 | ||
d3dd620b PM |
633 | /* |
634 | * Complex types, their bison value is struct f_val | |
635 | */ | |
e3f2d5fc | 636 | fipa: |
04632fd7 OZ |
637 | IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); } |
638 | | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); } | |
d3dd620b PM |
639 | ; |
640 | ||
b8cc390e OZ |
641 | |
642 | ||
643 | /* | |
644 | * Set constants. They are also used in switch cases. We use separate | |
645 | * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...) | |
646 | * to elude a collision between symbol (in expr) in set_atom and symbol | |
647 | * as a function call in switch case cmds. | |
648 | */ | |
649 | ||
38506f71 | 650 | set_atom: |
83715aa8 OZ |
651 | NUM { $$.type = T_INT; $$.val.i = $1; } |
652 | | fipa { $$ = $1; } | |
653 | | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | |
654 | | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | |
b2f00837 | 655 | | '(' term ')' { |
7afa1438 | 656 | if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); |
b2f00837 OZ |
657 | if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); |
658 | } | |
659 | | SYM { | |
660 | if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name); | |
661 | if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); | |
662 | $$ = *(struct f_val *)($1->def); | |
663 | } | |
b8cc390e | 664 | ; |
38506f71 | 665 | |
b8cc390e OZ |
666 | switch_atom: |
667 | NUM { $$.type = T_INT; $$.val.i = $1; } | |
668 | | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); } | |
b8cc390e OZ |
669 | | fipa { $$ = $1; } |
670 | | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | |
671 | ; | |
672 | ||
60566c5c OZ |
673 | cnum: |
674 | term { $$ = f_eval_int($1); } | |
b8cc390e OZ |
675 | |
676 | pair_item: | |
60566c5c OZ |
677 | '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } |
678 | | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); } | |
679 | | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); } | |
680 | | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); } | |
681 | | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); } | |
682 | | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); } | |
683 | | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); } | |
684 | | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); } | |
685 | | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); } | |
686 | | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')' | |
687 | { $$ = f_new_pair_item($2, $8, $4, $10); } | |
38506f71 PM |
688 | ; |
689 | ||
42a0c054 OZ |
690 | ec_kind: |
691 | RT { $$ = EC_RT; } | |
692 | | RO { $$ = EC_RO; } | |
693 | | UNKNOWN NUM { $$ = $2; } | |
694 | | GENERIC { $$ = EC_GENERIC; } | |
695 | ; | |
696 | ||
697 | ec_item: | |
60566c5c OZ |
698 | '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } |
699 | | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } | |
700 | | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } | |
42a0c054 OZ |
701 | ; |
702 | ||
60566c5c OZ |
703 | lc_item: |
704 | '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); } | |
705 | | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); } | |
706 | | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); } | |
707 | | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); } | |
708 | | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); } | |
709 | | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); } | |
710 | | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); } | |
711 | | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')' | |
712 | { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } | |
713 | ; | |
42a0c054 | 714 | |
b8cc390e OZ |
715 | set_item: |
716 | pair_item | |
42a0c054 | 717 | | ec_item |
60566c5c | 718 | | lc_item |
b8cc390e OZ |
719 | | set_atom { $$ = f_new_item($1, $1); } |
720 | | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } | |
721 | ; | |
722 | ||
723 | switch_item: | |
724 | pair_item | |
42a0c054 | 725 | | ec_item |
60566c5c | 726 | | lc_item |
b8cc390e OZ |
727 | | switch_atom { $$ = f_new_item($1, $1); } |
728 | | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } | |
729 | ; | |
730 | ||
38506f71 | 731 | set_items: |
b8cc390e OZ |
732 | set_item |
733 | | set_items ',' set_item { $$ = f_merge_items($1, $3); } | |
734 | ; | |
735 | ||
736 | switch_items: | |
737 | switch_item | |
738 | | switch_items ',' switch_item { $$ = f_merge_items($1, $3); } | |
38506f71 PM |
739 | ; |
740 | ||
b1a597e0 | 741 | fprefix: |
04632fd7 OZ |
742 | net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; } |
743 | | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; } | |
744 | | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; } | |
745 | | net_ip_ '{' NUM ',' NUM '}' { | |
5e173e9f | 746 | $$.net = $1; $$.lo = $3; $$.hi = $5; |
6aaaa635 OZ |
747 | if (($3 > $5) || ($5 > net_max_prefix_length[$1.type])) |
748 | cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5); | |
b1a597e0 OZ |
749 | } |
750 | ; | |
751 | ||
752 | fprefix_set: | |
04632fd7 OZ |
753 | fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); } |
754 | | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); } | |
b1a597e0 OZ |
755 | ; |
756 | ||
41be4444 | 757 | switch_body: /* EMPTY */ { $$ = NULL; } |
b8cc390e OZ |
758 | | switch_body switch_items ':' cmds { |
759 | /* Fill data fields */ | |
760 | struct f_tree *t; | |
761 | for (t = $2; t; t = t->left) | |
762 | t->data = $4; | |
763 | $$ = f_merge_items($1, $2); | |
41be4444 | 764 | } |
5e173e9f | 765 | | switch_body ELSECOL cmds { |
b8cc390e OZ |
766 | struct f_tree *t = f_new_tree(); |
767 | t->from.type = t->to.type = T_VOID; | |
768 | t->right = t; | |
769 | t->data = $3; | |
770 | $$ = f_merge_items($1, t); | |
771 | } | |
41be4444 | 772 | ; |
d3dd620b | 773 | |
7f0ac737 | 774 | /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $3; } */ |
e4a73dbf | 775 | |
92a72a4c | 776 | bgp_path_expr: |
c8cafc8e | 777 | symbol { $$ = $1; } |
92a72a4c OZ |
778 | | '(' term ')' { $$ = $2; } |
779 | ; | |
780 | ||
f9491630 | 781 | bgp_path: |
3e52d112 | 782 | PO bgp_path_tail PC { $$ = $2; } |
f9491630 OZ |
783 | ; |
784 | ||
3e52d112 JMM |
785 | bgp_path_tail: |
786 | NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } | |
787 | | NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; } | |
788 | | '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; } | |
789 | | '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; } | |
790 | | bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } | |
122deb6d | 791 | | { $$ = NULL; } |
f9491630 | 792 | ; |
77de6882 | 793 | |
23b1539b | 794 | constant: |
7f0ac737 MM |
795 | NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $1; } |
796 | | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 1; } | |
797 | | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 0; } | |
798 | | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a[1].p = $1; } | |
799 | | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a[0].p = val; *val = $1; } | |
800 | | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a[0].p = val; } | |
801 | | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a[0].p = val; } | |
802 | | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a[1].p = build_tree($2); DBG( "ook\n" ); } | |
803 | | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a[1].p = $2; } | |
804 | | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a[1].i = $1 & 0xffff; } | |
23b1539b PM |
805 | ; |
806 | ||
42a0c054 | 807 | constructor: |
78e33c29 OZ |
808 | '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } |
809 | | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } | |
66dbdbd9 | 810 | | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } |
e8bc64e3 | 811 | | bgp_path { $$ = f_generate_path_mask($1); } |
42a0c054 OZ |
812 | ; |
813 | ||
92a72a4c | 814 | |
2e18b87d | 815 | rtadot: /* EMPTY, we are not permitted RTA. prefix */ |
6c14255d | 816 | ; |
f4536657 | 817 | |
2d496d20 PM |
818 | function_call: |
819 | SYM '(' var_list ')' { | |
820 | struct symbol *sym; | |
821 | struct f_inst *inst = $3; | |
822 | if ($1->class != SYM_FUNCTION) | |
a5a947d4 | 823 | cf_error("You can't call something which is not a function. Really."); |
d4d75628 | 824 | DBG("You are calling function %s\n", $1->name); |
5a14df39 | 825 | $$ = f_new_inst(FI_CALL); |
7f0ac737 MM |
826 | $$->a[0].p = inst; |
827 | $$->a[1].p = $1->def; | |
083c43e2 | 828 | sym = $1->aux2; |
2d496d20 PM |
829 | while (sym || inst) { |
830 | if (!sym || !inst) | |
a5a947d4 | 831 | cf_error("Wrong number of arguments for function %s.", $1->name); |
d4d75628 | 832 | DBG( "You should pass parameter called %s\n", sym->name); |
7f0ac737 | 833 | inst->a[0].p = sym; |
083c43e2 | 834 | sym = sym->aux2; |
2d496d20 PM |
835 | inst = inst->next; |
836 | } | |
837 | } | |
838 | ; | |
839 | ||
92a72a4c OZ |
840 | symbol: |
841 | SYM { | |
265419a3 MM |
842 | switch ($1->class & 0xffff) { |
843 | case SYM_CONSTANT_RANGE: | |
844 | $$ = f_new_inst(FI_CONSTANT_INDIRECT); | |
845 | goto cv_common; | |
846 | case SYM_VARIABLE_RANGE: | |
847 | $$ = f_new_inst(FI_VARIABLE); | |
848 | cv_common: | |
7f0ac737 MM |
849 | $$->a[0].p = $1->def; |
850 | $$->a[1].p = $1->name; | |
265419a3 MM |
851 | break; |
852 | case SYM_ATTRIBUTE: | |
853 | $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); | |
854 | break; | |
855 | default: | |
856 | cf_error("%s: variable expected.", $1->name); | |
92a72a4c OZ |
857 | } |
858 | } | |
859 | ||
2bdb5e00 | 860 | static_attr: |
5a14df39 MJM |
861 | FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); } |
862 | | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); } | |
d1ba927b | 863 | | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); } |
5a14df39 MJM |
864 | | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); } |
865 | | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); } | |
866 | | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); } | |
5a14df39 | 867 | | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); } |
f2d8e680 | 868 | | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); } |
5a14df39 | 869 | | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); } |
2bdb5e00 PM |
870 | ; |
871 | ||
84c7e194 | 872 | term: |
5a14df39 | 873 | '(' term ')' { $$ = $2; } |
7f0ac737 MM |
874 | | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; } |
875 | | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; } | |
876 | | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; } | |
877 | | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; } | |
878 | | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; } | |
879 | | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; } | |
880 | | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; } | |
881 | | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; } | |
882 | | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; } | |
883 | | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; } | |
884 | | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; } | |
885 | | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; } | |
886 | | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; } | |
887 | | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; } | |
888 | | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; } | |
889 | | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; } | |
23b1539b | 890 | |
92a72a4c | 891 | | symbol { $$ = $1; } |
1183b6b2 | 892 | | constant { $$ = $1; } |
42a0c054 | 893 | | constructor { $$ = $1; } |
4515bdba | 894 | |
5a14df39 | 895 | | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); } |
2bdb5e00 | 896 | |
5a14df39 | 897 | | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); } |
fe613ecd | 898 | |
5a14df39 | 899 | | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); } |
36bbfc70 | 900 | |
7f0ac737 MM |
901 | | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; } |
902 | | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; } | |
903 | | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; } | |
904 | | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; } | |
905 | | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; } | |
906 | | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; } | |
907 | | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; } | |
908 | | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; } | |
909 | | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; } | |
910 | | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; } | |
911 | | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; } | |
912 | | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; } | |
7f77e250 PM |
913 | |
914 | /* Communities */ | |
10a53608 PM |
915 | /* This causes one shift/reduce conflict |
916 | | rtadot dynamic_attr '.' ADD '(' term ')' { } | |
917 | | rtadot dynamic_attr '.' DELETE '(' term ')' { } | |
918 | | rtadot dynamic_attr '.' CONTAINS '(' term ')' { } | |
a2d15746 | 919 | | rtadot dynamic_attr '.' RESET{ } |
10a53608 | 920 | */ |
7f77e250 | 921 | |
5a14df39 MJM |
922 | | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; } |
923 | | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; } | |
924 | | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; } | |
925 | | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; } | |
7f0ac737 MM |
926 | | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; } |
927 | | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; } | |
928 | | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; } | |
929 | | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; } | |
afc54517 | 930 | |
0264ccf6 PT |
931 | | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } |
932 | | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } | |
af582c48 | 933 | |
7f0ac737 | 934 | | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; } |
9b0a0ba9 | 935 | |
a2d15746 | 936 | /* | term '.' LEN { $$->code = P('P','l'); } */ |
7f77e250 | 937 | |
995e5894 PM |
938 | /* function_call is inlined here */ |
939 | | SYM '(' var_list ')' { | |
940 | struct symbol *sym; | |
941 | struct f_inst *inst = $3; | |
942 | if ($1->class != SYM_FUNCTION) | |
a5a947d4 | 943 | cf_error("You can't call something which is not a function. Really."); |
995e5894 | 944 | DBG("You are calling function %s\n", $1->name); |
5a14df39 | 945 | $$ = f_new_inst(FI_CALL); |
7f0ac737 MM |
946 | $$->a[0].p = inst; |
947 | $$->a[1].p = $1->def; | |
083c43e2 | 948 | sym = $1->aux2; |
995e5894 PM |
949 | while (sym || inst) { |
950 | if (!sym || !inst) | |
a5a947d4 | 951 | cf_error("Wrong number of arguments for function %s.", $1->name); |
995e5894 | 952 | DBG( "You should pass parameter called %s\n", sym->name); |
7f0ac737 | 953 | inst->a[0].p = sym; |
083c43e2 | 954 | sym = sym->aux2; |
995e5894 PM |
955 | inst = inst->next; |
956 | } | |
957 | } | |
ba921648 PM |
958 | ; |
959 | ||
960 | break_command: | |
03e3d184 MM |
961 | QUITBIRD { $$ = F_QUITBIRD; } |
962 | | ACCEPT { $$ = F_ACCEPT; } | |
963 | | REJECT { $$ = F_REJECT; } | |
964 | | ERROR { $$ = F_ERROR; } | |
965 | | PRINT { $$ = F_NOP; } | |
966 | | PRINTN { $$ = F_NONL; } | |
ba921648 PM |
967 | ; |
968 | ||
23b1539b | 969 | print_one: |
7f0ac737 | 970 | term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; } |
23b1539b PM |
971 | ; |
972 | ||
973 | print_list: /* EMPTY */ { $$ = NULL; } | |
995e5894 PM |
974 | | print_one { $$ = $1; } |
975 | | print_one ',' print_list { | |
23b1539b | 976 | if ($1) { |
995e5894 | 977 | $1->next = $3; |
23b1539b | 978 | $$ = $1; |
995e5894 | 979 | } else $$ = $3; |
23b1539b PM |
980 | } |
981 | ; | |
982 | ||
c8cafc8e | 983 | var_listn: term { |
5a14df39 | 984 | $$ = f_new_inst(FI_SET); |
7f0ac737 MM |
985 | $$->a[0].p = NULL; |
986 | $$->a[1].p = $1; | |
d3dd620b PM |
987 | $$->next = NULL; |
988 | } | |
6dc7a0cb | 989 | | term ',' var_listn { |
5a14df39 | 990 | $$ = f_new_inst(FI_SET); |
7f0ac737 MM |
991 | $$->a[0].p = NULL; |
992 | $$->a[1].p = $1; | |
6542ece9 PM |
993 | $$->next = $3; |
994 | } | |
995 | ; | |
996 | ||
6dc7a0cb PM |
997 | var_list: /* EMPTY */ { $$ = NULL; } |
998 | | var_listn { $$ = $1; } | |
999 | ; | |
1000 | ||
23b1539b | 1001 | cmd: |
49955645 | 1002 | IF term THEN block { |
5a14df39 | 1003 | $$ = f_new_inst(FI_CONDITION); |
7f0ac737 MM |
1004 | $$->a[0].p = $2; |
1005 | $$->a[1].p = $4; | |
23b1539b | 1006 | } |
49955645 | 1007 | | IF term THEN block ELSE block { |
5a14df39 | 1008 | $$ = f_new_inst(FI_CONDITION); |
7f0ac737 MM |
1009 | $$->a[0].p = $2; |
1010 | $$->a[1].p = $4; | |
1011 | $$->a[2].p = $6; | |
23b1539b | 1012 | } |
ba921648 | 1013 | | SYM '=' term ';' { |
d4d75628 | 1014 | DBG( "Ook, we'll set value\n" ); |
265419a3 MM |
1015 | if ($1->class == SYM_ATTRIBUTE) { |
1016 | $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def)); | |
7f0ac737 | 1017 | $$->a[0].p = $3; |
265419a3 MM |
1018 | } else if (($1->class & ~T_MASK) == SYM_VARIABLE) { |
1019 | $$ = f_new_inst(FI_SET); | |
7f0ac737 MM |
1020 | $$->a[0].p = $1; |
1021 | $$->a[1].p = $3; | |
265419a3 MM |
1022 | } else |
1023 | cf_error( "Symbol `%s' is read-only.", $1->name ); | |
b9d70dc8 | 1024 | } |
2d496d20 | 1025 | | RETURN term ';' { |
d4d75628 | 1026 | DBG( "Ook, we'll return the value\n" ); |
5a14df39 | 1027 | $$ = f_new_inst(FI_RETURN); |
7f0ac737 | 1028 | $$->a[0].p = $2; |
2d496d20 | 1029 | } |
db1326aa | 1030 | | rtadot dynamic_attr '=' term ';' { |
5a14df39 | 1031 | $$ = f_new_inst_da(FI_EA_SET, $2); |
7f0ac737 | 1032 | $$->a[0].p = $4; |
f31156ca | 1033 | } |
0dc4431c | 1034 | | rtadot static_attr '=' term ';' { |
5a14df39 | 1035 | $$ = f_new_inst_sa(FI_RTA_SET, $2); |
7f0ac737 | 1036 | if (!$$->a[0].i) |
0dc4431c | 1037 | cf_error( "This static attribute is read-only."); |
7f0ac737 | 1038 | $$->a[0].p = $4; |
0dc4431c PM |
1039 | } |
1040 | | PREFERENCE '=' term ';' { | |
5a14df39 | 1041 | $$ = f_new_inst(FI_PREF_SET); |
7f0ac737 | 1042 | $$->a[0].p = $3; |
c8cafc8e | 1043 | } |
db1326aa | 1044 | | UNSET '(' rtadot dynamic_attr ')' ';' { |
5a14df39 | 1045 | $$ = f_new_inst_da(FI_EA_SET, $4); |
9f4929e7 | 1046 | $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; |
7f0ac737 | 1047 | $$->a[0].p = NULL; |
c7b43f33 | 1048 | } |
7f0ac737 | 1049 | | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; } |
2d496d20 | 1050 | | function_call ';' { $$ = $1; } |
7db7b7db | 1051 | | CASE term '{' switch_body '}' { |
5a14df39 | 1052 | $$ = f_new_inst(FI_SWITCH); |
7f0ac737 MM |
1053 | $$->a[0].p = $2; |
1054 | $$->a[1].p = build_tree( $4 ); | |
7db7b7db | 1055 | } |
7d6eebae | 1056 | |
42a0c054 | 1057 | | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } |
5a14df39 MJM |
1058 | | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); } |
1059 | | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); } | |
1060 | | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); } | |
1061 | | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); } | |
3ec0bedc | 1062 | | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } |
9b0a0ba9 OZ |
1063 | ; |
1064 | ||
1065 | get_cf_position: | |
1066 | { | |
1067 | $$ = cf_text; | |
1068 | }; | |
1069 | ||
1070 | ||
b9d70dc8 | 1071 | CF_END |