]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Filter: recursion to loop
[thirdparty/bird.git] / filter / filter.c
CommitLineData
23b1539b
PM
1/*
2 * Filters: utility functions
3 *
4 * Copyright 1998 Pavel Machek <pavel@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
29818140 7 *
23b1539b
PM
8 */
9
2337ade7
PM
10/**
11 * DOC: Filters
12 *
725270cb
MM
13 * You can find sources of the filter language in |filter/|
14 * directory. File |filter/config.Y| contains filter grammar and basically translates
15 * the source from user into a tree of &f_inst structures. These trees are
16 * later interpreted using code in |filter/filter.c|.
fe613ecd 17 *
725270cb
MM
18 * A filter is represented by a tree of &f_inst structures, one structure per
19 * "instruction". Each &f_inst contains @code, @aux value which is
20 * usually the data type this instruction operates on and two generic
21 * arguments (@a1, @a2). Some instructions contain pointer(s) to other
22 * instructions in their (@a1, @a2) fields.
2337ade7 23 *
725270cb
MM
24 * Filters use a &f_val structure for their data. Each &f_val
25 * contains type and value (types are constants prefixed with %T_). Few
26 * of the types are special; %T_RETURN can be or-ed with a type to indicate
27 * that return from a function or from the whole filter should be
28 * forced. Important thing about &f_val's is that they may be copied
29 * with a simple |=|. That's fine for all currently defined types: strings
2337ade7 30 * are read-only (and therefore okay), paths are copied for each
4c5f93d7
PM
31 * operation (okay too).
32 */
2337ade7 33
9a220cab 34#undef LOCAL_DEBUG
6b9fa320 35
23b1539b
PM
36#include "nest/bird.h"
37#include "lib/lists.h"
38#include "lib/resource.h"
39#include "lib/socket.h"
38506f71 40#include "lib/string.h"
7f77e250 41#include "lib/unaligned.h"
23b1539b
PM
42#include "nest/route.h"
43#include "nest/protocol.h"
44#include "nest/iface.h"
159fa4ce 45#include "nest/attrs.h"
23b1539b
PM
46#include "conf/conf.h"
47#include "filter/filter.h"
48
38506f71
PM
49#define CMP_ERROR 999
50
9831e591 51static struct adata *
42a0c054 52adata_empty(struct linpool *pool, int l)
ad9074e9 53{
42a0c054
OZ
54 struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
55 res->length = l;
ad9074e9
PM
56 return res;
57}
58
11cb6202 59static void
0e175f9f 60pm_format(struct f_path_mask *p, buffer *buf)
11cb6202 61{
0e175f9f 62 buffer_puts(buf, "[= ");
11cb6202
OZ
63
64 while (p)
0e175f9f
OZ
65 {
66 switch(p->kind)
11cb6202 67 {
0e175f9f
OZ
68 case PM_ASN:
69 buffer_print(buf, "%u ", p->val);
70 break;
92a72a4c 71
0e175f9f
OZ
72 case PM_QUESTION:
73 buffer_puts(buf, "? ");
74 break;
92a72a4c 75
0e175f9f
OZ
76 case PM_ASTERISK:
77 buffer_puts(buf, "* ");
78 break;
11cb6202 79
a0fe1944
OF
80 case PM_ASN_RANGE:
81 buffer_print(buf, "%u..%u ", p->val, p->val2);
82 break;
83
0e175f9f
OZ
84 case PM_ASN_EXPR:
85 buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val));
86 break;
11cb6202
OZ
87 }
88
0e175f9f
OZ
89 p = p->next;
90 }
91
92 buffer_puts(buf, "=]");
11cb6202
OZ
93}
94
70c57805 95static inline int
0aeac9cb 96uint_cmp(uint i1, uint i2)
2dec1e34 97{
70c57805 98 return (int)(i1 > i2) - (int)(i1 < i2);
2dec1e34
OZ
99}
100
70c57805
OZ
101static inline int
102u64_cmp(u64 i1, u64 i2)
42a0c054 103{
70c57805 104 return (int)(i1 > i2) - (int)(i1 < i2);
42a0c054
OZ
105}
106
66dbdbd9
OZ
107static inline int
108lcomm_cmp(lcomm v1, lcomm v2)
109{
110 if (v1.asn != v2.asn)
111 return (v1.asn > v2.asn) ? 1 : -1;
112 if (v1.ldp1 != v2.ldp1)
113 return (v1.ldp1 > v2.ldp1) ? 1 : -1;
114 if (v1.ldp2 != v2.ldp2)
115 return (v1.ldp2 > v2.ldp2) ? 1 : -1;
116 return 0;
117}
118
8dcf2544 119/**
3e82b32d 120 * val_compare - compare two values
8dcf2544
PM
121 * @v1: first value
122 * @v2: second value
123 *
28a10f84
OZ
124 * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
125 * error. Tree module relies on this giving consistent results so
126 * that it can be used for building balanced trees.
b093c328 127 */
38506f71
PM
128int
129val_compare(struct f_val v1, struct f_val v2)
130{
d85e1f0e
MM
131 int rc;
132
f71bded6 133 if (v1.type != v2.type) {
70c57805
OZ
134 if (v1.type == T_VOID) /* Hack for else */
135 return -1;
136 if (v2.type == T_VOID)
137 return 1;
138
126683fe
OZ
139#ifndef IPV6
140 /* IP->Quad implicit conversion */
141 if ((v1.type == T_QUAD) && (v2.type == T_IP))
2dec1e34 142 return uint_cmp(v1.val.i, ipa_to_u32(v2.val.px.ip));
126683fe 143 if ((v1.type == T_IP) && (v2.type == T_QUAD))
2dec1e34 144 return uint_cmp(ipa_to_u32(v1.val.px.ip), v2.val.i);
126683fe
OZ
145#endif
146
f71bded6 147 debug( "Types do not match in val_compare\n" );
7db7b7db 148 return CMP_ERROR;
f71bded6 149 }
28a10f84 150
38506f71 151 switch (v1.type) {
28a10f84
OZ
152 case T_VOID:
153 return 0;
f4536657 154 case T_ENUM:
a6c9f064
OF
155 case T_INT:
156 case T_BOOL:
d3dd620b 157 case T_PAIR:
126683fe 158 case T_QUAD:
2dec1e34 159 return uint_cmp(v1.val.i, v2.val.i);
42a0c054
OZ
160 case T_EC:
161 return u64_cmp(v1.val.ec, v2.val.ec);
66dbdbd9
OZ
162 case T_LC:
163 return lcomm_cmp(v1.val.lc, v2.val.lc);
43fc099b 164 case T_IP:
6dc7a0cb 165 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
d85e1f0e
MM
166 case T_PREFIX:
167 if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
168 return rc;
52e030e1 169 return uint_cmp(v1.val.px.len, v2.val.px.len);
e29fa06e
OZ
170 case T_STRING:
171 return strcmp(v1.val.s, v2.val.s);
3076b5ae
MM
172 default:
173 return CMP_ERROR;
38506f71
PM
174 }
175}
176
28a10f84 177static int
122deb6d 178pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
dfd48621 179{
28a10f84
OZ
180 while (m1 && m2)
181 {
122deb6d 182 if (m1->kind != m2->kind)
28a10f84
OZ
183 return 0;
184
122deb6d
OZ
185 if (m1->kind == PM_ASN_EXPR)
186 {
187 if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
188 return 0;
189 }
190 else
191 {
192 if ((m1->val != m2->val) || (m1->val2 != m2->val2))
193 return 0;
194 }
195
28a10f84
OZ
196 m1 = m1->next;
197 m2 = m2->next;
198 }
199
33d22f0e 200 return !m1 && !m2;
28a10f84
OZ
201}
202
203/**
204 * val_same - compare two values
205 * @v1: first value
206 * @v2: second value
207 *
208 * Compares two values and returns 1 if they are same and 0 if not.
209 * Comparison of values of different types is valid and returns 0.
210 */
211int
212val_same(struct f_val v1, struct f_val v2)
dfd48621 213{
28a10f84
OZ
214 int rc;
215
216 rc = val_compare(v1, v2);
217 if (rc != CMP_ERROR)
218 return !rc;
219
220 if (v1.type != v2.type)
221 return 0;
222
223 switch (v1.type) {
224 case T_PATH_MASK:
122deb6d 225 return pm_same(v1.val.path_mask, v2.val.path_mask);
28a10f84
OZ
226 case T_PATH:
227 case T_CLIST:
228 case T_ECLIST:
66dbdbd9 229 case T_LCLIST:
28a10f84
OZ
230 return adata_same(v1.val.ad, v2.val.ad);
231 case T_SET:
232 return same_tree(v1.val.t, v2.val.t);
233 case T_PREFIX_SET:
234 return trie_same(v1.val.ti, v2.val.ti);
235 default:
236 bug("Invalid type in val_same(): %x", v1.type);
237 }
dfd48621 238}
b1a597e0
OZ
239
240void
7f0d245a 241fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
b1a597e0
OZ
242{
243 *l = *h = px->len & LEN_MASK;
244
245 if (px->len & LEN_MINUS)
246 *l = 0;
247
248 else if (px->len & LEN_PLUS)
249 *h = MAX_PREFIX_LENGTH;
250
251 else if (px->len & LEN_RANGE)
252 {
253 *l = 0xff & (px->len >> 16);
254 *h = 0xff & (px->len >> 8);
255 }
256}
257
ba5c0057
OZ
258static int
259clist_set_type(struct f_tree *set, struct f_val *v)
260{
261 switch (set->from.type) {
262 case T_PAIR:
263 v->type = T_PAIR;
264 return 1;
265 case T_QUAD:
266#ifndef IPV6
267 case T_IP:
268#endif
269 v->type = T_QUAD;
270 return 1;
271 break;
272 default:
273 v->type = T_VOID;
274 return 0;
275 }
276}
277
42a0c054
OZ
278static inline int
279eclist_set_type(struct f_tree *set)
280{ return set->from.type == T_EC; }
281
66dbdbd9
OZ
282static inline int
283lclist_set_type(struct f_tree *set)
284{ return set->from.type == T_LC; }
285
ba5c0057
OZ
286static int
287clist_match_set(struct adata *clist, struct f_tree *set)
288{
289 if (!clist)
290 return 0;
291
292 struct f_val v;
293 if (!clist_set_type(set, &v))
294 return CMP_ERROR;
295
296 u32 *l = (u32 *) clist->data;
297 u32 *end = l + clist->length/4;
42a0c054 298
ba5c0057
OZ
299 while (l < end) {
300 v.val.i = *l++;
301 if (find_tree(set, v))
302 return 1;
303 }
304 return 0;
305}
306
42a0c054
OZ
307static int
308eclist_match_set(struct adata *list, struct f_tree *set)
309{
310 if (!list)
311 return 0;
312
313 if (!eclist_set_type(set))
314 return CMP_ERROR;
315
316 struct f_val v;
317 u32 *l = int_set_get_data(list);
318 int len = int_set_get_size(list);
319 int i;
320
321 v.type = T_EC;
322 for (i = 0; i < len; i += 2) {
323 v.val.ec = ec_get(l, i);
324 if (find_tree(set, v))
325 return 1;
326 }
327
328 return 0;
329}
330
66dbdbd9
OZ
331static int
332lclist_match_set(struct adata *list, struct f_tree *set)
333{
334 if (!list)
335 return 0;
336
337 if (!lclist_set_type(set))
338 return CMP_ERROR;
339
340 struct f_val v;
341 u32 *l = int_set_get_data(list);
342 int len = int_set_get_size(list);
343 int i;
344
345 v.type = T_LC;
346 for (i = 0; i < len; i += 3) {
347 v.val.lc = lc_get(l, i);
348 if (find_tree(set, v))
349 return 1;
350 }
351
352 return 0;
353}
354
ba5c0057 355static struct adata *
0888a737 356clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
ba5c0057 357{
0888a737 358 if (!list)
ba5c0057
OZ
359 return NULL;
360
0888a737 361 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
ba5c0057 362 struct f_val v;
0888a737
OZ
363 if (tree)
364 clist_set_type(set.val.t, &v);
365 else
366 v.type = T_PAIR;
ba5c0057 367
0888a737
OZ
368 int len = int_set_get_size(list);
369 u32 *l = int_set_get_data(list);
370 u32 tmp[len];
ba5c0057 371 u32 *k = tmp;
0888a737 372 u32 *end = l + len;
ba5c0057
OZ
373
374 while (l < end) {
375 v.val.i = *l++;
0888a737
OZ
376 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
377 if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
ba5c0057
OZ
378 *k++ = v.val.i;
379 }
380
3e236955 381 uint nl = (k - tmp) * sizeof(u32);
0888a737
OZ
382 if (nl == list->length)
383 return list;
ba5c0057 384
42a0c054
OZ
385 struct adata *res = adata_empty(pool, nl);
386 memcpy(res->data, tmp, nl);
387 return res;
388}
389
390static struct adata *
0888a737 391eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
42a0c054
OZ
392{
393 if (!list)
394 return NULL;
395
0888a737 396 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
42a0c054
OZ
397 struct f_val v;
398
399 int len = int_set_get_size(list);
400 u32 *l = int_set_get_data(list);
401 u32 tmp[len];
402 u32 *k = tmp;
403 int i;
404
405 v.type = T_EC;
406 for (i = 0; i < len; i += 2) {
407 v.val.ec = ec_get(l, i);
0888a737
OZ
408 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
409 if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
42a0c054
OZ
410 *k++ = l[i];
411 *k++ = l[i+1];
412 }
413 }
414
3e236955 415 uint nl = (k - tmp) * sizeof(u32);
42a0c054
OZ
416 if (nl == list->length)
417 return list;
418
419 struct adata *res = adata_empty(pool, nl);
ba5c0057
OZ
420 memcpy(res->data, tmp, nl);
421 return res;
422}
423
66dbdbd9
OZ
424static struct adata *
425lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
426{
427 if (!list)
428 return NULL;
429
430 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
431 struct f_val v;
432
433 int len = int_set_get_size(list);
434 u32 *l = int_set_get_data(list);
435 u32 tmp[len];
436 u32 *k = tmp;
437 int i;
438
439 v.type = T_LC;
440 for (i = 0; i < len; i += 3) {
441 v.val.lc = lc_get(l, i);
442 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
443 if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
444 k = lc_copy(k, l+i);
445 }
446
3e236955 447 uint nl = (k - tmp) * sizeof(u32);
66dbdbd9
OZ
448 if (nl == list->length)
449 return list;
450
451 struct adata *res = adata_empty(pool, nl);
452 memcpy(res->data, tmp, nl);
453 return res;
454}
455
8dcf2544 456/**
3e82b32d 457 * val_in_range - implement |~| operator
8dcf2544
PM
458 * @v1: element
459 * @v2: set
460 *
b655596d 461 * Checks if @v1 is element (|~| operator) of @v2.
b093c328 462 */
9831e591 463static int
7db7b7db
PM
464val_in_range(struct f_val v1, struct f_val v2)
465{
b655596d
OZ
466 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
467 return as_path_match(v1.val.ad, v2.val.path_mask);
6dc7a0cb 468
b655596d 469 if ((v1.type == T_INT) && (v2.type == T_PATH))
a15dab76 470 return as_path_contains(v2.val.ad, v1.val.i, 1);
6dc7a0cb 471
b655596d
OZ
472 if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
473 return int_set_contains(v2.val.ad, v1.val.i);
474#ifndef IPV6
475 /* IP->Quad implicit conversion */
476 if ((v1.type == T_IP) && (v2.type == T_CLIST))
477 return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
478#endif
b1a597e0 479
b655596d
OZ
480 if ((v1.type == T_EC) && (v2.type == T_ECLIST))
481 return ec_set_contains(v2.val.ad, v1.val.ec);
ba5c0057 482
66dbdbd9
OZ
483 if ((v1.type == T_LC) && (v2.type == T_LCLIST))
484 return lc_set_contains(v2.val.ad, v1.val.lc);
485
b655596d
OZ
486 if ((v1.type == T_STRING) && (v2.type == T_STRING))
487 return patmatch(v2.val.s, v1.val.s);
42a0c054 488
b655596d
OZ
489 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
490 return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
7db7b7db 491
b655596d
OZ
492 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
493 return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
0d1b3c4c 494
b1a597e0 495 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
7f0d245a 496 return trie_match_fprefix(v2.val.ti, &v1.val.px);
0d1b3c4c 497
b655596d
OZ
498 if (v2.type != T_SET)
499 return CMP_ERROR;
0d1b3c4c 500
b655596d
OZ
501 /* With integrated Quad<->IP implicit conversion */
502 if ((v1.type == v2.val.t->from.type) ||
503 ((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP)))
504 return !!find_tree(v2.val.t, v1);
0d1b3c4c 505
b655596d 506 if (v1.type == T_CLIST)
ba5c0057 507 return clist_match_set(v1.val.ad, v2.val.t);
0d1b3c4c 508
b655596d 509 if (v1.type == T_ECLIST)
42a0c054
OZ
510 return eclist_match_set(v1.val.ad, v2.val.t);
511
66dbdbd9
OZ
512 if (v1.type == T_LCLIST)
513 return lclist_match_set(v1.val.ad, v2.val.t);
514
b655596d 515 if (v1.type == T_PATH)
cc31b75a
OZ
516 return as_path_match_set(v1.val.ad, v2.val.t);
517
7db7b7db 518 return CMP_ERROR;
38506f71
PM
519}
520
4c5f93d7 521/*
0e175f9f 522 * val_format - format filter value
b093c328 523 */
508d9360 524void
0e175f9f 525val_format(struct f_val v, buffer *buf)
38506f71 526{
ecd25633 527 char buf2[1024];
0e175f9f
OZ
528 switch (v.type)
529 {
530 case T_VOID: buffer_puts(buf, "(void)"); return;
531 case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
52e030e1 532 case T_INT: buffer_print(buf, "%u", v.val.i); return;
0e175f9f
OZ
533 case T_STRING: buffer_print(buf, "%s", v.val.s); return;
534 case T_IP: buffer_print(buf, "%I", v.val.px.ip); return;
535 case T_PREFIX: buffer_print(buf, "%I/%d", v.val.px.ip, v.val.px.len); return;
52e030e1 536 case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
0e175f9f
OZ
537 case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
538 case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
66dbdbd9 539 case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
0e175f9f
OZ
540 case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
541 case T_SET: tree_format(v.val.t, buf); return;
52e030e1 542 case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
0e175f9f
OZ
543 case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
544 case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
545 case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
66dbdbd9 546 case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
0e175f9f
OZ
547 case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
548 default: buffer_print(buf, "[unknown type %x]", v.type); return;
38506f71 549 }
38506f71
PM
550}
551
a03ede64
OZ
552static struct rte **f_rte;
553static struct rta *f_old_rta;
31e79264 554static struct ea_list **f_tmp_attrs;
a03ede64 555static struct linpool *f_pool;
0e175f9f 556static struct buffer f_buf;
0a06a9b8 557static int f_flags;
36bbfc70 558
a03ede64
OZ
559static inline void f_rte_cow(void)
560{
315f23a0 561 *f_rte = rte_cow(*f_rte);
a03ede64
OZ
562}
563
4c5f93d7 564/*
b093c328
PM
565 * rta_cow - prepare rta for modification by filter
566 */
9831e591 567static void
a03ede64 568f_rta_cow(void)
26c09e1d 569{
8d9eef17
OZ
570 if (!rta_is_cached((*f_rte)->attrs))
571 return;
572
573 /* Prepare to modify rte */
574 f_rte_cow();
575
576 /* Store old rta to free it later, it stores reference from rte_cow() */
577 f_old_rta = (*f_rte)->attrs;
578
579 /*
580 * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
581 * with f_old_rta (they will be copied when the cached rta will be obtained
582 * at the end of f_run()), also the lock of hostentry is inherited (we
583 * suppose hostentry is not changed by filters).
584 */
585 (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool);
26c09e1d
PM
586}
587
1123e707 588static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
cb530392 589
9a4037d4 590#define runtime(x) do { \
b9405791
OZ
591 if (!(f_flags & FF_SILENT)) \
592 log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
9a4037d4
PM
593 res.type = T_RETURN; \
594 res.val.i = F_ERROR; \
595 return res; \
596 } while(0)
597
598#define ARG(x,y) \
599 x = interpret(what->y); \
2d496d20 600 if (x.type & T_RETURN) \
9a4037d4
PM
601 return x;
602
603#define ONEARG ARG(v1, a1.p)
604#define TWOARGS ARG(v1, a1.p) \
605 ARG(v2, a2.p)
606#define TWOARGS_C TWOARGS \
607 if (v1.type != v2.type) \
b178d92a 608 runtime( "Can't operate with values of incompatible types" );
508d9360
OZ
609#define ACCESS_RTE \
610 do { if (!f_rte) runtime("No route to access"); } while (0)
7db7b7db 611
315f23a0
OZ
612#define BITFIELD_MASK(what) \
613 (1u << (what->a2.i >> 24))
614
b093c328
PM
615/**
616 * interpret
2e9b2421 617 * @what: filter to interpret
b093c328 618 *
4c5f93d7 619 * Interpret given tree of filter instructions. This is core function
b093c328 620 * of filter system and does all the hard work.
771ae456
PM
621 *
622 * Each instruction has 4 fields: code (which is instruction code),
623 * aux (which is extension to instruction code, typically type),
624 * arg1 and arg2 - arguments. Depending on instruction, arguments
315f23a0 625 * are either integers, or pointers to instruction trees. Common
771ae456
PM
626 * instructions like +, that have two expressions as arguments use
627 * TWOARGS macro to get both of them evaluated.
628 *
629 * &f_val structures are copied around, so there are no problems with
630 * memory managment.
b093c328 631 */
23b1539b
PM
632static struct f_val
633interpret(struct f_inst *what)
634{
635 struct symbol *sym;
7c601e6b 636 struct f_val v1, v2, res = { .type = T_VOID }, *vp;
92a72a4c 637 unsigned u1, u2;
6a57bb31 638 int i;
7ea5b00f 639 u32 as;
23b1539b 640
7c601e6b 641 for ( ; what; what = what->next) {
23b1539b 642 res.type = T_VOID;
5a14df39
MJM
643 switch(what->fi_code) {
644 case FI_COMMA:
23b1539b
PM
645 TWOARGS;
646 break;
647
648/* Binary operators */
5a14df39 649 case FI_ADD:
23b1539b
PM
650 TWOARGS_C;
651 switch (res.type = v1.type) {
b178d92a 652 case T_VOID: runtime( "Can't operate with values of type void" );
23b1539b
PM
653 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
654 default: runtime( "Usage of unknown type" );
655 }
656 break;
5a14df39 657 case FI_SUBTRACT:
9f0d45d6
PM
658 TWOARGS_C;
659 switch (res.type = v1.type) {
b178d92a 660 case T_VOID: runtime( "Can't operate with values of type void" );
9f0d45d6
PM
661 case T_INT: res.val.i = v1.val.i - v2.val.i; break;
662 default: runtime( "Usage of unknown type" );
663 }
664 break;
5a14df39 665 case FI_MULTIPLY:
9f0d45d6
PM
666 TWOARGS_C;
667 switch (res.type = v1.type) {
b178d92a 668 case T_VOID: runtime( "Can't operate with values of type void" );
9f0d45d6
PM
669 case T_INT: res.val.i = v1.val.i * v2.val.i; break;
670 default: runtime( "Usage of unknown type" );
671 }
672 break;
5a14df39 673 case FI_DIVIDE:
23b1539b
PM
674 TWOARGS_C;
675 switch (res.type = v1.type) {
b178d92a 676 case T_VOID: runtime( "Can't operate with values of type void" );
64ba9f7b
PM
677 case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
678 res.val.i = v1.val.i / v2.val.i; break;
23b1539b
PM
679 default: runtime( "Usage of unknown type" );
680 }
681 break;
315f23a0 682
5a14df39
MJM
683 case FI_AND:
684 case FI_OR:
0aa88530
OZ
685 ARG(v1, a1.p);
686 if (v1.type != T_BOOL)
687 runtime( "Can't do boolean operation on non-booleans" );
5a14df39 688 if (v1.val.i == (what->fi_code == FI_OR)) {
0aa88530
OZ
689 res.type = T_BOOL;
690 res.val.i = v1.val.i;
691 break;
692 }
693
694 ARG(v2, a2.p);
695 if (v2.type != T_BOOL)
696 runtime( "Can't do boolean operation on non-booleans" );
697 res.type = T_BOOL;
698 res.val.i = v2.val.i;
5f4aee76 699 break;
23b1539b 700
5a14df39 701 case FI_PAIR_CONSTRUCT:
42a0c054 702 TWOARGS;
92a72a4c
OZ
703 if ((v1.type != T_INT) || (v2.type != T_INT))
704 runtime( "Can't operate with value of non-integer type in pair constructor" );
705 u1 = v1.val.i;
706 u2 = v2.val.i;
707 if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
708 runtime( "Can't operate with value out of bounds in pair constructor" );
709 res.val.i = (u1 << 16) | u2;
710 res.type = T_PAIR;
711 break;
712
5a14df39 713 case FI_EC_CONSTRUCT:
42a0c054
OZ
714 {
715 TWOARGS;
716
717 int check, ipv4_used;
718 u32 key, val;
719
720 if (v1.type == T_INT) {
721 ipv4_used = 0; key = v1.val.i;
315f23a0 722 }
42a0c054
OZ
723 else if (v1.type == T_QUAD) {
724 ipv4_used = 1; key = v1.val.i;
725 }
726#ifndef IPV6
727 /* IP->Quad implicit conversion */
728 else if (v1.type == T_IP) {
729 ipv4_used = 1; key = ipa_to_u32(v1.val.px.ip);
730 }
731#endif
732 else
733 runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
734
735 if (v2.type != T_INT)
736 runtime("Can't operate with value of non-integer type in EC constructor");
737 val = v2.val.i;
738
66dbdbd9 739 /* XXXX */
42a0c054
OZ
740 res.type = T_EC;
741
742 if (what->aux == EC_GENERIC) {
743 check = 0; res.val.ec = ec_generic(key, val);
744 }
745 else if (ipv4_used) {
746 check = 1; res.val.ec = ec_ip4(what->aux, key, val);
747 }
748 else if (key < 0x10000) {
749 check = 0; res.val.ec = ec_as2(what->aux, key, val);
750 }
751 else {
752 check = 1; res.val.ec = ec_as4(what->aux, key, val);
753 }
754
755 if (check && (val > 0xFFFF))
756 runtime("Can't operate with value out of bounds in EC constructor");
757
758 break;
759 }
760
5a14df39 761 case FI_LC_CONSTRUCT:
66dbdbd9
OZ
762 {
763 TWOARGS;
764
765 /* Third argument hack */
766 struct f_val v3 = interpret(INST3(what).p);
767 if (v3.type & T_RETURN)
768 return v3;
769
770 if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT))
771 runtime( "Can't operate with value of non-integer type in LC constructor" );
772
773 res.type = T_LC;
774 res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
775
776 break;
777 }
778
23b1539b 779/* Relational operators */
38506f71
PM
780
781#define COMPARE(x) \
126683fe 782 TWOARGS; \
38506f71
PM
783 i = val_compare(v1, v2); \
784 if (i==CMP_ERROR) \
126683fe
OZ
785 runtime( "Can't compare values of incompatible types" ); \
786 res.type = T_BOOL; \
38506f71 787 res.val.i = (x); \
23b1539b 788 break;
38506f71 789
28a10f84
OZ
790#define SAME(x) \
791 TWOARGS; \
792 i = val_same(v1, v2); \
793 res.type = T_BOOL; \
794 res.val.i = (x); \
795 break;
796
5a14df39
MJM
797 case FI_NEQ: SAME(!i);
798 case FI_EQ: SAME(i);
799 case FI_LT: COMPARE(i==-1);
800 case FI_LTE: COMPARE(i!=1);
38506f71 801
5a14df39 802 case FI_NOT:
995e5894
PM
803 ONEARG;
804 if (v1.type != T_BOOL)
b178d92a 805 runtime( "Not applied to non-boolean" );
995e5894
PM
806 res = v1;
807 res.val.i = !res.val.i;
808 break;
809
5a14df39 810 case FI_MATCH:
38506f71 811 TWOARGS;
23b1539b 812 res.type = T_BOOL;
7db7b7db
PM
813 res.val.i = val_in_range(v1, v2);
814 if (res.val.i == CMP_ERROR)
815 runtime( "~ applied on unknown type pair" );
0aa88530 816 res.val.i = !!res.val.i;
23b1539b 817 break;
768d5e10 818
5a14df39 819 case FI_NOT_MATCH:
768d5e10
PT
820 TWOARGS;
821 res.type = T_BOOL;
822 res.val.i = val_in_range(v1, v2);
823 if (res.val.i == CMP_ERROR)
824 runtime( "!~ applied on unknown type pair" );
825 res.val.i = !res.val.i;
826 break;
827
5a14df39 828 case FI_DEFINED:
f4536657
PM
829 ONEARG;
830 res.type = T_BOOL;
831 res.val.i = (v1.type != T_VOID);
832 break;
23b1539b 833
d3dd620b 834 /* Set to indirect value, a1 = variable, a2 = value */
5a14df39 835 case FI_SET:
2db3b288
PM
836 ARG(v2, a2.p);
837 sym = what->a1.p;
126683fe
OZ
838 vp = sym->def;
839 if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) {
840#ifndef IPV6
841 /* IP->Quad implicit conversion */
842 if ((sym->class == (SYM_VARIABLE | T_QUAD)) && (v2.type == T_IP)) {
843 vp->type = T_QUAD;
844 vp->val.i = ipa_to_u32(v2.val.px.ip);
845 break;
846 }
847#endif
aa461248 848 runtime( "Assigning to variable of incompatible type" );
126683fe 849 }
315f23a0 850 *vp = v2;
23b1539b
PM
851 break;
852
083c43e2 853 /* some constants have value in a2, some in *a1.p, strange. */
5a14df39 854 case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */
c7b43f33 855 res.type = what->aux;
083c43e2 856
b1a597e0
OZ
857 if (res.type == T_PREFIX_SET)
858 res.val.ti = what->a2.p;
859 else if (res.type == T_SET)
083c43e2
OZ
860 res.val.t = what->a2.p;
861 else if (res.type == T_STRING)
862 res.val.s = what->a2.p;
863 else
864 res.val.i = what->a2.i;
23b1539b 865 break;
5a14df39
MJM
866 case FI_VARIABLE:
867 case FI_CONSTANT_INDIRECT:
38506f71
PM
868 res = * ((struct f_val *) what->a1.p);
869 break;
5a14df39 870 case FI_PRINT:
23b1539b 871 ONEARG;
0e175f9f 872 val_format(v1, &f_buf);
23b1539b 873 break;
5a14df39 874 case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */
23b1539b
PM
875 ONEARG;
876 if (v1.type != T_BOOL)
98da26a0 877 runtime( "If requires boolean expression" );
23b1539b 878 if (v1.val.i) {
2db3b288 879 ARG(res,a2.p);
23b1539b
PM
880 res.val.i = 0;
881 } else res.val.i = 1;
882 res.type = T_BOOL;
883 break;
5a14df39 884 case FI_NOP:
3cf4a2e2 885 debug( "No operation\n" );
23b1539b 886 break;
5a14df39 887 case FI_PRINT_AND_DIE:
23b1539b 888 ONEARG;
b9405791
OZ
889 if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
890 !(f_flags & FF_SILENT))
0e175f9f 891 log_commit(*L_INFO, &f_buf);
23b1539b 892
2db3b288 893 switch (what->a2.i) {
23b1539b
PM
894 case F_QUITBIRD:
895 die( "Filter asked me to die" );
896 case F_ACCEPT:
897 /* Should take care about turning ACCEPT into MODIFY */
898 case F_ERROR:
2ad6dcdb 899 case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
23b1539b 900 res.type = T_RETURN;
2ad6dcdb 901 res.val.i = what->a2.i;
7e1f9971 902 return res; /* We have to return now, no more processing. */
d3dd620b 903 case F_NONL:
23b1539b
PM
904 case F_NOP:
905 break;
906 default:
b178d92a 907 bug( "unknown return type: Can't happen");
23b1539b
PM
908 }
909 break;
5a14df39 910 case FI_RTA_GET: /* rta access */
36bbfc70 911 {
508d9360 912 ACCESS_RTE;
36bbfc70 913 struct rta *rta = (*f_rte)->attrs;
c7b43f33 914 res.type = what->aux;
a5fc5958
OZ
915
916 switch (what->a2.i)
917 {
918 case SA_FROM: res.val.px.ip = rta->from; break;
919 case SA_GW: res.val.px.ip = rta->gw; break;
920 case SA_NET: res.val.px.ip = (*f_rte)->net->n.prefix;
921 res.val.px.len = (*f_rte)->net->n.pxlen; break;
736e143f 922 case SA_PROTO: res.val.s = rta->src->proto->name; break;
a5fc5958
OZ
923 case SA_SOURCE: res.val.i = rta->source; break;
924 case SA_SCOPE: res.val.i = rta->scope; break;
925 case SA_CAST: res.val.i = rta->cast; break;
926 case SA_DEST: res.val.i = rta->dest; break;
927 case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break;
928 case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break;
929
36bbfc70 930 default:
a5fc5958 931 bug("Invalid static attribute access (%x)", res.type);
36bbfc70
PM
932 }
933 }
934 break;
5a14df39 935 case FI_RTA_SET:
508d9360 936 ACCESS_RTE;
0dc4431c
PM
937 ONEARG;
938 if (what->aux != v1.type)
98da26a0 939 runtime( "Attempt to set static attribute to incompatible type" );
a5fc5958 940
a03ede64 941 f_rta_cow();
0dc4431c
PM
942 {
943 struct rta *rta = (*f_rte)->attrs;
182a7895 944
a5fc5958
OZ
945 switch (what->a2.i)
946 {
947 case SA_FROM:
948 rta->from = v1.val.px.ip;
0dc4431c 949 break;
182a7895 950
a5fc5958 951 case SA_GW:
00192d5a 952 {
a5fc5958 953 ip_addr ip = v1.val.px.ip;
736e143f 954 neighbor *n = neigh_find(rta->src->proto, &ip, 0);
00192d5a
OZ
955 if (!n || (n->scope == SCOPE_HOST))
956 runtime( "Invalid gw address" );
957
958 rta->dest = RTD_ROUTER;
959 rta->gw = ip;
960 rta->iface = n->iface;
961 rta->nexthops = NULL;
962 rta->hostentry = NULL;
963 }
0dc4431c 964 break;
182a7895 965
a5fc5958 966 case SA_SCOPE:
182a7895
OZ
967 rta->scope = v1.val.i;
968 break;
969
a5fc5958 970 case SA_DEST:
182a7895
OZ
971 i = v1.val.i;
972 if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
973 runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
00192d5a 974
182a7895
OZ
975 rta->dest = i;
976 rta->gw = IPA_NONE;
977 rta->iface = NULL;
978 rta->nexthops = NULL;
00192d5a 979 rta->hostentry = NULL;
182a7895
OZ
980 break;
981
0dc4431c 982 default:
a5fc5958 983 bug("Invalid static attribute access (%x)", res.type);
0dc4431c
PM
984 }
985 }
986 break;
5a14df39 987 case FI_EA_GET: /* Access to extended attributes */
508d9360 988 ACCESS_RTE;
91447965 989 {
0a06a9b8 990 eattr *e = NULL;
315f23a0
OZ
991 u16 code = what->a2.i;
992
3076b5ae 993 if (!(f_flags & FF_FORCE_TMPATTR))
315f23a0
OZ
994 e = ea_find((*f_rte)->attrs->eattrs, code);
995 if (!e)
996 e = ea_find((*f_tmp_attrs), code);
3076b5ae 997 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
315f23a0 998 e = ea_find((*f_rte)->attrs->eattrs, code);
e8da1bd0
OZ
999
1000 if (!e) {
0277cc0b
OZ
1001 /* A special case: undefined int_set looks like empty int_set */
1002 if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
1003 res.type = T_CLIST;
42a0c054
OZ
1004 res.val.ad = adata_empty(f_pool, 0);
1005 break;
1006 }
315f23a0 1007
42a0c054 1008 /* The same special case for ec_set */
315f23a0 1009 if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
42a0c054
OZ
1010 res.type = T_ECLIST;
1011 res.val.ad = adata_empty(f_pool, 0);
0277cc0b
OZ
1012 break;
1013 }
42a0c054 1014
66dbdbd9
OZ
1015 /* The same special case for lc_set */
1016 if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
1017 res.type = T_LCLIST;
1018 res.val.ad = adata_empty(f_pool, 0);
1019 break;
1020 }
1021
e8da1bd0
OZ
1022 /* Undefined value */
1023 res.type = T_VOID;
1024 break;
1025 }
1026
1027 switch (what->aux & EAF_TYPE_MASK) {
1028 case EAF_TYPE_INT:
0150e521 1029 res.type = T_INT;
91447965
PM
1030 res.val.i = e->u.data;
1031 break;
126683fe
OZ
1032 case EAF_TYPE_ROUTER_ID:
1033 res.type = T_QUAD;
1034 res.val.i = e->u.data;
1035 break;
e8da1bd0
OZ
1036 case EAF_TYPE_OPAQUE:
1037 res.type = T_ENUM_EMPTY;
1038 res.val.i = 0;
1039 break;
330aecea 1040 case EAF_TYPE_IP_ADDRESS:
330aecea
OZ
1041 res.type = T_IP;
1042 struct adata * ad = e->u.ptr;
1043 res.val.px.ip = * (ip_addr *) ad->data;
1044 break;
0150e521
PM
1045 case EAF_TYPE_AS_PATH:
1046 res.type = T_PATH;
1047 res.val.ad = e->u.ptr;
1048 break;
315f23a0
OZ
1049 case EAF_TYPE_BITFIELD:
1050 res.type = T_BOOL;
1051 res.val.i = !!(e->u.data & BITFIELD_MASK(what));
1052 break;
0150e521
PM
1053 case EAF_TYPE_INT_SET:
1054 res.type = T_CLIST;
10a53608
PM
1055 res.val.ad = e->u.ptr;
1056 break;
42a0c054
OZ
1057 case EAF_TYPE_EC_SET:
1058 res.type = T_ECLIST;
1059 res.val.ad = e->u.ptr;
1060 break;
66dbdbd9
OZ
1061 case EAF_TYPE_LC_SET:
1062 res.type = T_LCLIST;
1063 res.val.ad = e->u.ptr;
1064 break;
e8da1bd0
OZ
1065 case EAF_TYPE_UNDEF:
1066 res.type = T_VOID;
1067 break;
2803c9dd 1068 default:
ad9074e9 1069 bug("Unknown type in e,a");
91447965
PM
1070 }
1071 }
6dc7a0cb 1072 break;
5a14df39 1073 case FI_EA_SET:
508d9360 1074 ACCESS_RTE;
f31156ca 1075 ONEARG;
f31156ca
PM
1076 {
1077 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
315f23a0 1078 u16 code = what->a2.i;
f31156ca
PM
1079
1080 l->next = NULL;
1081 l->flags = EALF_SORTED;
1082 l->count = 1;
315f23a0 1083 l->attrs[0].id = code;
913ce95b
PM
1084 l->attrs[0].flags = 0;
1085 l->attrs[0].type = what->aux | EAF_ORIGINATED;
315f23a0 1086
31e79264
PM
1087 switch (what->aux & EAF_TYPE_MASK) {
1088 case EAF_TYPE_INT:
5a8b1fb0
MV
1089 // Enums are also ints, so allow them in.
1090 if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
31e79264 1091 runtime( "Setting int attribute to non-int value" );
f31156ca
PM
1092 l->attrs[0].u.data = v1.val.i;
1093 break;
3e40f3e7
OZ
1094
1095 case EAF_TYPE_ROUTER_ID:
1096#ifndef IPV6
1097 /* IP->Quad implicit conversion */
1098 if (v1.type == T_IP) {
1099 l->attrs[0].u.data = ipa_to_u32(v1.val.px.ip);
1100 break;
1101 }
1102#endif
1103 /* T_INT for backward compatibility */
1104 if ((v1.type != T_QUAD) && (v1.type != T_INT))
1105 runtime( "Setting quad attribute to non-quad value" );
1106 l->attrs[0].u.data = v1.val.i;
1107 break;
1108
e8da1bd0
OZ
1109 case EAF_TYPE_OPAQUE:
1110 runtime( "Setting opaque attribute is not allowed" );
1111 break;
330aecea
OZ
1112 case EAF_TYPE_IP_ADDRESS:
1113 if (v1.type != T_IP)
1114 runtime( "Setting ip attribute to non-ip value" );
1115 int len = sizeof(ip_addr);
1116 struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) + len);
1117 ad->length = len;
1118 (* (ip_addr *) ad->data) = v1.val.px.ip;
54fe0d92 1119 l->attrs[0].u.ptr = ad;
330aecea 1120 break;
10a53608
PM
1121 case EAF_TYPE_AS_PATH:
1122 if (v1.type != T_PATH)
1123 runtime( "Setting path attribute to non-path value" );
1124 l->attrs[0].u.ptr = v1.val.ad;
1125 break;
315f23a0
OZ
1126 case EAF_TYPE_BITFIELD:
1127 if (v1.type != T_BOOL)
1128 runtime( "Setting bit in bitfield attribute to non-bool value" );
1129 {
1130 /* First, we have to find the old value */
1131 eattr *e = NULL;
1132 if (!(f_flags & FF_FORCE_TMPATTR))
1133 e = ea_find((*f_rte)->attrs->eattrs, code);
1134 if (!e)
1135 e = ea_find((*f_tmp_attrs), code);
1136 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
1137 e = ea_find((*f_rte)->attrs->eattrs, code);
1138 u32 data = e ? e->u.data : 0;
1139
1140 if (v1.val.i)
1141 l->attrs[0].u.data = data | BITFIELD_MASK(what);
1142 else
1143 l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
1144 }
1145 break;
708711c3
PM
1146 case EAF_TYPE_INT_SET:
1147 if (v1.type != T_CLIST)
42a0c054
OZ
1148 runtime( "Setting clist attribute to non-clist value" );
1149 l->attrs[0].u.ptr = v1.val.ad;
1150 break;
1151 case EAF_TYPE_EC_SET:
1152 if (v1.type != T_ECLIST)
1153 runtime( "Setting eclist attribute to non-eclist value" );
708711c3
PM
1154 l->attrs[0].u.ptr = v1.val.ad;
1155 break;
66dbdbd9
OZ
1156 case EAF_TYPE_LC_SET:
1157 if (v1.type != T_LCLIST)
1158 runtime( "Setting lclist attribute to non-lclist value" );
1159 l->attrs[0].u.ptr = v1.val.ad;
1160 break;
31e79264
PM
1161 case EAF_TYPE_UNDEF:
1162 if (v1.type != T_VOID)
1163 runtime( "Setting void attribute to non-void value" );
48f9e019
PM
1164 l->attrs[0].u.data = 0;
1165 break;
0150e521 1166 default: bug("Unknown type in e,S");
f31156ca 1167 }
31e79264 1168
3076b5ae 1169 if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
a03ede64 1170 f_rta_cow();
db96fccb
OZ
1171 l->next = (*f_rte)->attrs->eattrs;
1172 (*f_rte)->attrs->eattrs = l;
31e79264
PM
1173 } else {
1174 l->next = (*f_tmp_attrs);
1175 (*f_tmp_attrs) = l;
1176 }
f31156ca 1177 }
f31156ca 1178 break;
5a14df39 1179 case FI_PREF_GET:
508d9360 1180 ACCESS_RTE;
0dc4431c
PM
1181 res.type = T_INT;
1182 res.val.i = (*f_rte)->pref;
1183 break;
5a14df39 1184 case FI_PREF_SET:
508d9360 1185 ACCESS_RTE;
0dc4431c
PM
1186 ONEARG;
1187 if (v1.type != T_INT)
b178d92a 1188 runtime( "Can't set preference to non-integer" );
7d37bf79 1189 if (v1.val.i > 0xFFFF)
f4c6ca8c 1190 runtime( "Setting preference value out of bounds" );
a03ede64 1191 f_rte_cow();
0dc4431c
PM
1192 (*f_rte)->pref = v1.val.i;
1193 break;
5a14df39 1194 case FI_LENGTH: /* Get length of */
684c6f5a
PM
1195 ONEARG;
1196 res.type = T_INT;
1197 switch(v1.type) {
1198 case T_PREFIX: res.val.i = v1.val.px.len; break;
1199 case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
7ccb36d3
OZ
1200 case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
1201 case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
66dbdbd9 1202 case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
7ccb36d3 1203 default: runtime( "Prefix, path, clist or eclist expected" );
684c6f5a
PM
1204 }
1205 break;
5a14df39 1206 case FI_IP: /* Convert prefix to ... */
36bbfc70
PM
1207 ONEARG;
1208 if (v1.type != T_PREFIX)
b178d92a 1209 runtime( "Prefix expected" );
c7b43f33 1210 res.type = what->aux;
36bbfc70 1211 switch(res.type) {
684c6f5a 1212 /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
6dc7a0cb 1213 case T_IP: res.val.px.ip = v1.val.px.ip; break;
3076b5ae 1214 default: bug( "Unknown prefix to conversion" );
36bbfc70
PM
1215 }
1216 break;
5a14df39 1217 case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
7ea5b00f
OZ
1218 ONEARG;
1219 if (v1.type != T_PATH)
2eece54a 1220 runtime( "AS path expected" );
7ea5b00f
OZ
1221
1222 as = 0;
52b9b2a1 1223 as_path_get_first(v1.val.ad, &as);
7ea5b00f
OZ
1224 res.type = T_INT;
1225 res.val.i = as;
1226 break;
5a14df39 1227 case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */
7ea5b00f
OZ
1228 ONEARG;
1229 if (v1.type != T_PATH)
1230 runtime( "AS path expected" );
1231
1232 as = 0;
52b9b2a1 1233 as_path_get_last(v1.val.ad, &as);
7ea5b00f
OZ
1234 res.type = T_INT;
1235 res.val.i = as;
1236 break;
5a14df39 1237 case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */
9c9cc35c
OZ
1238 ONEARG;
1239 if (v1.type != T_PATH)
1240 runtime( "AS path expected" );
1241
1242 res.type = T_INT;
1243 res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
1244 break;
5a14df39 1245 case FI_RETURN:
2d496d20
PM
1246 ONEARG;
1247 res = v1;
1248 res.type |= T_RETURN;
44711e0c 1249 return res;
5a14df39 1250 case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */
6542ece9
PM
1251 ONEARG;
1252 res = interpret(what->a2.p);
2d496d20
PM
1253 if (res.type == T_RETURN)
1254 return res;
315f23a0 1255 res.type &= ~T_RETURN;
6542ece9 1256 break;
5a14df39 1257 case FI_CLEAR_LOCAL_VARS: /* Clear local variables */
aa461248
OZ
1258 for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
1259 ((struct f_val *) sym->def)->type = T_VOID;
1260 break;
5a14df39 1261 case FI_SWITCH:
7db7b7db 1262 ONEARG;
41be4444
PM
1263 {
1264 struct f_tree *t = find_tree(what->a2.p, v1);
1265 if (!t) {
1266 v1.type = T_VOID;
1267 t = find_tree(what->a2.p, v1);
1268 if (!t) {
ad9074e9 1269 debug( "No else statement?\n");
41be4444
PM
1270 break;
1271 }
315f23a0 1272 }
1877dab2 1273 /* It is actually possible to have t->data NULL */
44711e0c
OZ
1274
1275 res = interpret(t->data);
1276 if (res.type & T_RETURN)
1277 return res;
41be4444 1278 }
7db7b7db 1279 break;
5a14df39 1280 case FI_IP_MASK: /* IP.MASK(val) */
f4536657
PM
1281 TWOARGS;
1282 if (v2.type != T_INT)
b178d92a 1283 runtime( "Integer expected");
f4536657 1284 if (v1.type != T_IP)
b178d92a 1285 runtime( "You can mask only IP addresses" );
f4536657
PM
1286 {
1287 ip_addr mask = ipa_mkmask(v2.val.i);
1288 res.type = T_IP;
1289 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
1290 }
d3dd620b 1291 break;
afc54517 1292
5a14df39 1293 case FI_EMPTY: /* Create empty attribute */
afc54517 1294 res.type = what->aux;
42a0c054 1295 res.val.ad = adata_empty(f_pool, 0);
afc54517 1296 break;
5a14df39 1297 case FI_PATH_PREPEND: /* Path prepend */
afc54517
PM
1298 TWOARGS;
1299 if (v1.type != T_PATH)
1300 runtime("Can't prepend to non-path");
1301 if (v2.type != T_INT)
1302 runtime("Can't prepend non-integer");
1303
1304 res.type = T_PATH;
1305 res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
1306 break;
1307
5a14df39 1308 case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */
9c400ec9 1309 TWOARGS;
bff9ce51
OZ
1310 if (v1.type == T_PATH)
1311 {
1312 struct f_tree *set = NULL;
1313 u32 key = 0;
1314 int pos;
1315
1316 if (v2.type == T_INT)
1317 key = v2.val.i;
1318 else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
1319 set = v2.val.t;
1320 else
1321 runtime("Can't delete non-integer (set)");
1322
1323 switch (what->aux)
1324 {
1325 case 'a': runtime("Can't add to path");
1326 case 'd': pos = 0; break;
1327 case 'f': pos = 1; break;
1328 default: bug("unknown Ca operation");
1329 }
1330
1331 if (pos && !set)
1332 runtime("Can't filter integer");
1333
1334 res.type = T_PATH;
1335 res.val.ad = as_path_filter(f_pool, v1.val.ad, set, key, pos);
1336 }
1337 else if (v1.type == T_CLIST)
42a0c054
OZ
1338 {
1339 /* Community (or cluster) list */
1340 struct f_val dummy;
1341 int arg_set = 0;
52e030e1 1342 uint n = 0;
a58022a6 1343
42a0c054 1344 if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
52e030e1 1345 n = v2.val.i;
126683fe 1346#ifndef IPV6
42a0c054
OZ
1347 /* IP->Quad implicit conversion */
1348 else if (v2.type == T_IP)
52e030e1 1349 n = ipa_to_u32(v2.val.px.ip);
126683fe 1350#endif
42a0c054
OZ
1351 else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
1352 arg_set = 1;
0888a737
OZ
1353 else if (v2.type == T_CLIST)
1354 arg_set = 2;
42a0c054
OZ
1355 else
1356 runtime("Can't add/delete non-pair");
1357
1358 res.type = T_CLIST;
1359 switch (what->aux)
1360 {
1361 case 'a':
0888a737 1362 if (arg_set == 1)
42a0c054 1363 runtime("Can't add set");
0888a737 1364 else if (!arg_set)
52e030e1 1365 res.val.ad = int_set_add(f_pool, v1.val.ad, n);
315f23a0 1366 else
0888a737 1367 res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
42a0c054 1368 break;
315f23a0 1369
42a0c054
OZ
1370 case 'd':
1371 if (!arg_set)
52e030e1 1372 res.val.ad = int_set_del(f_pool, v1.val.ad, n);
42a0c054 1373 else
0888a737 1374 res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0);
42a0c054 1375 break;
9c400ec9 1376
42a0c054
OZ
1377 case 'f':
1378 if (!arg_set)
1379 runtime("Can't filter pair");
0888a737 1380 res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1);
42a0c054
OZ
1381 break;
1382
1383 default:
1384 bug("unknown Ca operation");
1385 }
1386 }
1387 else if (v1.type == T_ECLIST)
e08d2ff0 1388 {
42a0c054
OZ
1389 /* Extended community list */
1390 int arg_set = 0;
315f23a0 1391
42a0c054
OZ
1392 /* v2.val is either EC or EC-set */
1393 if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
1394 arg_set = 1;
0888a737
OZ
1395 else if (v2.type == T_ECLIST)
1396 arg_set = 2;
42a0c054 1397 else if (v2.type != T_EC)
66dbdbd9 1398 runtime("Can't add/delete non-ec");
42a0c054
OZ
1399
1400 res.type = T_ECLIST;
1401 switch (what->aux)
1402 {
1403 case 'a':
0888a737 1404 if (arg_set == 1)
42a0c054 1405 runtime("Can't add set");
0888a737
OZ
1406 else if (!arg_set)
1407 res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
315f23a0 1408 else
0888a737 1409 res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
42a0c054 1410 break;
315f23a0 1411
42a0c054
OZ
1412 case 'd':
1413 if (!arg_set)
1414 res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
1415 else
0888a737 1416 res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0);
42a0c054 1417 break;
e08d2ff0 1418
42a0c054
OZ
1419 case 'f':
1420 if (!arg_set)
1421 runtime("Can't filter ec");
0888a737 1422 res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1);
42a0c054 1423 break;
e08d2ff0 1424
42a0c054
OZ
1425 default:
1426 bug("unknown Ca operation");
1427 }
9c400ec9 1428 }
66dbdbd9
OZ
1429 else if (v1.type == T_LCLIST)
1430 {
1431 /* Large community list */
1432 int arg_set = 0;
1433
1434 /* v2.val is either LC or LC-set */
1435 if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
1436 arg_set = 1;
1437 else if (v2.type == T_LCLIST)
1438 arg_set = 2;
1439 else if (v2.type != T_LC)
1440 runtime("Can't add/delete non-lc");
1441
1442 res.type = T_LCLIST;
1443 switch (what->aux)
1444 {
1445 case 'a':
1446 if (arg_set == 1)
1447 runtime("Can't add set");
1448 else if (!arg_set)
1449 res.val.ad = lc_set_add(f_pool, v1.val.ad, v2.val.lc);
1450 else
1451 res.val.ad = lc_set_union(f_pool, v1.val.ad, v2.val.ad);
1452 break;
1453
1454 case 'd':
1455 if (!arg_set)
1456 res.val.ad = lc_set_del(f_pool, v1.val.ad, v2.val.lc);
1457 else
1458 res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 0);
1459 break;
1460
1461 case 'f':
1462 if (!arg_set)
1463 runtime("Can't filter lc");
1464 res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 1);
1465 break;
1466
1467 default:
1468 bug("unknown Ca operation");
1469 }
1470 }
42a0c054 1471 else
66dbdbd9 1472 runtime("Can't add/delete to non-[e|l]clist");
42a0c054 1473
9c400ec9
PM
1474 break;
1475
5a14df39 1476 case FI_ROA_CHECK: /* ROA Check */
af582c48
OZ
1477 if (what->arg1)
1478 {
1479 TWOARGS;
1480 if ((v1.type != T_PREFIX) || (v2.type != T_INT))
1481 runtime("Invalid argument to roa_check()");
1482
1483 as = v2.val.i;
1484 }
1485 else
1486 {
508d9360 1487 ACCESS_RTE;
af582c48
OZ
1488 v1.val.px.ip = (*f_rte)->net->n.prefix;
1489 v1.val.px.len = (*f_rte)->net->n.pxlen;
1490
1491 /* We ignore temporary attributes, probably not a problem here */
1492 /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
1493 eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02));
1494
1495 if (!e || e->type != EAF_TYPE_AS_PATH)
1496 runtime("Missing AS_PATH attribute");
1497
1498 as_path_get_last(e->u.ptr, &as);
1499 }
1500
1501 struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
1502 if (!rtc->table)
1503 runtime("Missing ROA table");
1504
1505 res.type = T_ENUM_ROA;
1506 res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
1507 break;
1508
23b1539b 1509 default:
5a14df39 1510 bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
7c601e6b 1511 }}
23b1539b
PM
1512 return res;
1513}
1514
2d496d20 1515#undef ARG
9a4037d4
PM
1516#define ARG(x,y) \
1517 if (!i_same(f1->y, f2->y)) \
1518 return 0;
1519
1520#define ONEARG ARG(v1, a1.p)
1521#define TWOARGS ARG(v1, a1.p) \
1522 ARG(v2, a2.p)
1523
1524#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
1525
4c5f93d7 1526/*
b093c328
PM
1527 * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
1528 */
9a4037d4
PM
1529int
1530i_same(struct f_inst *f1, struct f_inst *f2)
1531{
9a4037d4
PM
1532 if ((!!f1) != (!!f2))
1533 return 0;
d4d75628
PM
1534 if (!f1)
1535 return 1;
9a4037d4
PM
1536 if (f1->aux != f2->aux)
1537 return 0;
5a14df39 1538 if (f1->fi_code != f2->fi_code)
9a4037d4 1539 return 0;
d4d75628
PM
1540 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
1541 return 1;
9a4037d4 1542
5a14df39
MJM
1543 switch(f1->fi_code) {
1544 case FI_COMMA: /* fall through */
1545 case FI_ADD:
1546 case FI_SUBTRACT:
1547 case FI_MULTIPLY:
1548 case FI_DIVIDE:
1549 case FI_OR:
1550 case FI_AND:
1551 case FI_PAIR_CONSTRUCT:
1552 case FI_EC_CONSTRUCT:
1553 case FI_NEQ:
1554 case FI_EQ:
1555 case FI_LT:
1556 case FI_LTE: TWOARGS; break;
1557
1558 case FI_NOT: ONEARG; break;
1559 case FI_NOT_MATCH:
1560 case FI_MATCH: TWOARGS; break;
1561 case FI_DEFINED: ONEARG; break;
1562
1563 case FI_LC_CONSTRUCT:
66dbdbd9
OZ
1564 TWOARGS;
1565 if (!i_same(INST3(f1).p, INST3(f2).p))
1566 return 0;
1567 break;
1568
5a14df39 1569 case FI_SET:
9a4037d4
PM
1570 ARG(v2, a2.p);
1571 {
1572 struct symbol *s1, *s2;
1573 s1 = f1->a1.p;
1574 s2 = f2->a1.p;
1575 if (strcmp(s1->name, s2->name))
1576 return 0;
1577 if (s1->class != s2->class)
1578 return 0;
1579 }
1580 break;
1581
5a14df39 1582 case FI_CONSTANT:
b1a597e0
OZ
1583 switch (f1->aux) {
1584
1585 case T_PREFIX_SET:
1586 if (!trie_same(f1->a2.p, f2->a2.p))
1587 return 0;
9be1086d 1588 break;
b1a597e0
OZ
1589
1590 case T_SET:
4bb18dd2
PM
1591 if (!same_tree(f1->a2.p, f2->a2.p))
1592 return 0;
9be1086d 1593 break;
b1a597e0 1594
4bb18dd2
PM
1595 case T_STRING:
1596 if (strcmp(f1->a2.p, f2->a2.p))
1597 return 0;
1598 break;
b1a597e0 1599
4bb18dd2
PM
1600 default:
1601 A2_SAME;
1602 }
1603 break;
507e182a 1604
5a14df39 1605 case FI_CONSTANT_INDIRECT:
28a10f84 1606 if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
9a4037d4
PM
1607 return 0;
1608 break;
28a10f84 1609
5a14df39 1610 case FI_VARIABLE:
9be1086d
OF
1611 if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
1612 return 0;
1613 break;
5a14df39
MJM
1614 case FI_PRINT: case FI_LENGTH: ONEARG; break;
1615 case FI_CONDITION: TWOARGS; break;
1616 case FI_NOP: case FI_EMPTY: break;
1617 case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
1618 case FI_PREF_GET:
1619 case FI_RTA_GET: A2_SAME; break;
1620 case FI_EA_GET: A2_SAME; break;
1621 case FI_PREF_SET:
1622 case FI_RTA_SET:
1623 case FI_EA_SET: ONEARG; A2_SAME; break;
1624
1625 case FI_RETURN: ONEARG; break;
1626 case FI_IP: ONEARG; break;
1627 case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
315f23a0 1628 ONEARG;
d4d75628 1629 if (!i_same(f1->a2.p, f2->a2.p))
315f23a0 1630 return 0;
d4d75628
PM
1631 f2->a2.p = f1->a2.p;
1632 break;
5a14df39
MJM
1633 case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
1634 case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
1635 case FI_IP_MASK: TWOARGS; break;
1636 case FI_PATH_PREPEND: TWOARGS; break;
1637 case FI_CLIST_ADD_DEL: TWOARGS; break;
1638 case FI_AS_PATH_FIRST:
1639 case FI_AS_PATH_LAST:
1640 case FI_AS_PATH_LAST_NAG: ONEARG; break;
1641 case FI_ROA_CHECK:
af582c48
OZ
1642 TWOARGS;
1643 /* Does not really make sense - ROA check resuls may change anyway */
315f23a0 1644 if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
af582c48
OZ
1645 ((struct f_inst_roa_check *) f2)->rtc->name))
1646 return 0;
1647 break;
9a4037d4 1648 default:
5a14df39 1649 bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
9a4037d4
PM
1650 }
1651 return i_same(f1->next, f2->next);
1652}
1653
ff95080f 1654/**
a03ede64
OZ
1655 * f_run - run a filter for a route
1656 * @filter: filter to run
1657 * @rte: route being filtered, may be modified
1658 * @tmp_attrs: temporary attributes, prepared by caller or generated by f_run()
ff95080f 1659 * @tmp_pool: all filter allocations go from this pool
4c5f93d7 1660 * @flags: flags
a03ede64
OZ
1661 *
1662 * If filter needs to modify the route, there are several
1663 * posibilities. @rte might be read-only (with REF_COW flag), in that
1664 * case rw copy is obtained by rte_cow() and @rte is replaced. If
1665 * @rte is originally rw, it may be directly modified (and it is never
1666 * copied).
1667 *
1668 * The returned rte may reuse the (possibly cached, cloned) rta, or
1669 * (if rta was modificied) contains a modified uncached rta, which
1670 * uses parts allocated from @tmp_pool and parts shared from original
1671 * rta. There is one exception - if @rte is rw but contains a cached
1672 * rta and that is modified, rta in returned rte is also cached.
1673 *
1674 * Ownership of cached rtas is consistent with rte, i.e.
1675 * if a new rte is returned, it has its own clone of cached rta
1676 * (and cached rta of read-only source rte is intact), if rte is
1677 * modified in place, old cached rta is possibly freed.
ff95080f 1678 */
23b1539b 1679int
0a06a9b8 1680f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
23b1539b 1681{
36da2857
OZ
1682 if (filter == FILTER_ACCEPT)
1683 return F_ACCEPT;
1684
1685 if (filter == FILTER_REJECT)
1686 return F_REJECT;
1687
a03ede64 1688 int rte_cow = ((*rte)->flags & REF_COW);
6b9fa320 1689 DBG( "Running filter `%s'...", filter->name );
23b1539b 1690
36bbfc70 1691 f_rte = rte;
a03ede64
OZ
1692 f_old_rta = NULL;
1693 f_tmp_attrs = tmp_attrs;
f31156ca 1694 f_pool = tmp_pool;
a03ede64 1695 f_flags = flags;
0d1b3c4c 1696
0e175f9f
OZ
1697 LOG_BUFFER_INIT(f_buf);
1698
a03ede64
OZ
1699 struct f_val res = interpret(filter->root);
1700
1701 if (f_old_rta) {
1702 /*
1703 * Cached rta was modified and f_rte contains now an uncached one,
1704 * sharing some part with the cached one. The cached rta should
1705 * be freed (if rte was originally COW, f_old_rta is a clone
1706 * obtained during rte_cow()).
1707 *
1708 * This also implements the exception mentioned in f_run()
1709 * description. The reason for this is that rta reuses parts of
1710 * f_old_rta, and these may be freed during rta_free(f_old_rta).
1711 * This is not the problem if rte was COW, because original rte
1712 * also holds the same rta.
1713 */
1714 if (!rte_cow)
1715 (*f_rte)->attrs = rta_lookup((*f_rte)->attrs);
1716
1717 rta_free(f_old_rta);
1718 }
1719
0d1b3c4c 1720
0b1cad81 1721 if (res.type != T_RETURN) {
b9405791
OZ
1722 if (!(f_flags & FF_SILENT))
1723 log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
23b1539b 1724 return F_ERROR;
0b1cad81 1725 }
52e030e1 1726 DBG( "done (%u)\n", res.val.i );
23b1539b
PM
1727 return res.val.i;
1728}
1729
1321e12a
OZ
1730/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
1731
1732struct f_val
1733f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
1734{
1735 struct ea_list *tmp_attrs = NULL;
1736
1737 f_rte = rte;
1738 f_old_rta = NULL;
1739 f_tmp_attrs = &tmp_attrs;
1740 f_pool = tmp_pool;
1741 f_flags = 0;
1742
1743 LOG_BUFFER_INIT(f_buf);
1744
1745 /* Note that in this function we assume that rte->attrs is private / uncached */
1746 struct f_val res = interpret(expr);
1747
1748 /* Hack to include EAF_TEMP attributes to the main list */
1749 (*rte)->attrs->eattrs = ea_append(tmp_attrs, (*rte)->attrs->eattrs);
1750
1751 return res;
1752}
1753
508d9360
OZ
1754struct f_val
1755f_eval(struct f_inst *expr, struct linpool *tmp_pool)
1c20608e 1756{
b1c9d871
MM
1757 f_flags = 0;
1758 f_tmp_attrs = NULL;
1759 f_rte = NULL;
508d9360 1760 f_pool = tmp_pool;
0d1b3c4c 1761
0e175f9f
OZ
1762 LOG_BUFFER_INIT(f_buf);
1763
508d9360
OZ
1764 return interpret(expr);
1765}
0d1b3c4c 1766
52e030e1 1767uint
508d9360
OZ
1768f_eval_int(struct f_inst *expr)
1769{
1770 /* Called independently in parse-time to eval expressions */
1771 struct f_val res = f_eval(expr, cfg_mem);
0d1b3c4c 1772
b1c9d871
MM
1773 if (res.type != T_INT)
1774 cf_error("Integer expression expected");
508d9360 1775
b1c9d871
MM
1776 return res.val.i;
1777}
1c20608e 1778
92a72a4c
OZ
1779u32
1780f_eval_asn(struct f_inst *expr)
1781{
0d1b3c4c 1782 /* Called as a part of another interpret call, therefore no log_reset() */
92a72a4c 1783 struct f_val res = interpret(expr);
938b191b 1784 return (res.type == T_INT) ? res.val.i : 0;
92a72a4c
OZ
1785}
1786
ff95080f
PM
1787/**
1788 * filter_same - compare two filters
1789 * @new: first filter to be compared
1790 * @old: second filter to be compared, notice that this filter is
1791 * damaged while comparing.
1792 *
1793 * Returns 1 in case filters are same, otherwise 0. If there are
1794 * underlying bugs, it will rather say 0 on same filters than say
1795 * 1 on different.
1796 */
30a6108c
MM
1797int
1798filter_same(struct filter *new, struct filter *old)
1799{
81ce667b
MM
1800 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
1801 return 1;
1802 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
1803 new == FILTER_ACCEPT || new == FILTER_REJECT)
1804 return 0;
9a4037d4 1805 return i_same(new->root, old->root);
30a6108c 1806}