]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Filter refactoring: The instructions are converted to the switch body by M4
[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
7f0ac737
MM
21 * arguments (@a[0], @a[1]). Some instructions contain pointer(s) to other
22 * instructions in their (@a[0], @a[1]) 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"
0264ccf6
PT
42#include "lib/net.h"
43#include "lib/ip.h"
23b1539b
PM
44#include "nest/route.h"
45#include "nest/protocol.h"
46#include "nest/iface.h"
159fa4ce 47#include "nest/attrs.h"
23b1539b
PM
48#include "conf/conf.h"
49#include "filter/filter.h"
50
38506f71
PM
51#define CMP_ERROR 999
52
fc8df41e
JMM
53#define FILTER_STACK_DEPTH 16384
54
55/* Filter interpreter stack. Make this thread local after going parallel. */
56struct filter_stack {
57 struct f_val val;
58};
59
60static struct filter_stack filter_stack[FILTER_STACK_DEPTH];
61
a946317f
JMM
62/* Internal filter state, to be allocated on stack when executing filters */
63struct filter_state {
64 struct rte **rte;
65 struct rta *old_rta;
66 struct ea_list **eattrs;
67 struct linpool *pool;
68 struct buffer buf;
fc8df41e
JMM
69 struct filter_stack *stack;
70 int stack_ptr;
a946317f
JMM
71 int flags;
72};
73
9b0a0ba9
OZ
74void (*bt_assert_hook)(int result, struct f_inst *assert);
75
8f8671bc
OZ
76static struct adata undef_adata; /* adata of length 0 used for undefined */
77
78/* Special undef value for paths and clists */
79static inline int
80undef_value(struct f_val v)
81{
82 return ((v.type == T_PATH) || (v.type == T_CLIST) ||
83 (v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
84 (v.val.ad == &undef_adata);
85}
86
9831e591 87static struct adata *
42a0c054 88adata_empty(struct linpool *pool, int l)
ad9074e9 89{
42a0c054
OZ
90 struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
91 res->length = l;
ad9074e9
PM
92 return res;
93}
94
11cb6202 95static void
0e175f9f 96pm_format(struct f_path_mask *p, buffer *buf)
11cb6202 97{
0e175f9f 98 buffer_puts(buf, "[= ");
11cb6202
OZ
99
100 while (p)
0e175f9f
OZ
101 {
102 switch(p->kind)
11cb6202 103 {
0e175f9f
OZ
104 case PM_ASN:
105 buffer_print(buf, "%u ", p->val);
106 break;
92a72a4c 107
0e175f9f
OZ
108 case PM_QUESTION:
109 buffer_puts(buf, "? ");
110 break;
92a72a4c 111
0e175f9f
OZ
112 case PM_ASTERISK:
113 buffer_puts(buf, "* ");
114 break;
11cb6202 115
a0fe1944
OF
116 case PM_ASN_RANGE:
117 buffer_print(buf, "%u..%u ", p->val, p->val2);
118 break;
119
0e175f9f 120 case PM_ASN_EXPR:
e8bc64e3 121 ASSERT(0);
11cb6202
OZ
122 }
123
0e175f9f
OZ
124 p = p->next;
125 }
126
127 buffer_puts(buf, "=]");
11cb6202
OZ
128}
129
5e173e9f
JMM
130static inline int val_is_ip4(const struct f_val v)
131{ return (v.type == T_IP) && ipa_is_ip4(v.val.ip); }
42a0c054 132
66dbdbd9
OZ
133static inline int
134lcomm_cmp(lcomm v1, lcomm v2)
135{
136 if (v1.asn != v2.asn)
137 return (v1.asn > v2.asn) ? 1 : -1;
138 if (v1.ldp1 != v2.ldp1)
139 return (v1.ldp1 > v2.ldp1) ? 1 : -1;
140 if (v1.ldp2 != v2.ldp2)
141 return (v1.ldp2 > v2.ldp2) ? 1 : -1;
142 return 0;
143}
144
8dcf2544 145/**
3e82b32d 146 * val_compare - compare two values
8dcf2544
PM
147 * @v1: first value
148 * @v2: second value
149 *
28a10f84
OZ
150 * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
151 * error. Tree module relies on this giving consistent results so
152 * that it can be used for building balanced trees.
b093c328 153 */
38506f71
PM
154int
155val_compare(struct f_val v1, struct f_val v2)
156{
f71bded6 157 if (v1.type != v2.type) {
70c57805
OZ
158 if (v1.type == T_VOID) /* Hack for else */
159 return -1;
160 if (v2.type == T_VOID)
161 return 1;
162
126683fe 163 /* IP->Quad implicit conversion */
5e173e9f
JMM
164 if ((v1.type == T_QUAD) && val_is_ip4(v2))
165 return uint_cmp(v1.val.i, ipa_to_u32(v2.val.ip));
166 if (val_is_ip4(v1) && (v2.type == T_QUAD))
167 return uint_cmp(ipa_to_u32(v1.val.ip), v2.val.i);
126683fe 168
f71bded6 169 debug( "Types do not match in val_compare\n" );
7db7b7db 170 return CMP_ERROR;
f71bded6 171 }
28a10f84 172
38506f71 173 switch (v1.type) {
28a10f84
OZ
174 case T_VOID:
175 return 0;
f4536657 176 case T_ENUM:
a6c9f064
OF
177 case T_INT:
178 case T_BOOL:
d3dd620b 179 case T_PAIR:
126683fe 180 case T_QUAD:
2dec1e34 181 return uint_cmp(v1.val.i, v2.val.i);
42a0c054 182 case T_EC:
8c9986d3 183 case T_RD:
42a0c054 184 return u64_cmp(v1.val.ec, v2.val.ec);
66dbdbd9
OZ
185 case T_LC:
186 return lcomm_cmp(v1.val.lc, v2.val.lc);
43fc099b 187 case T_IP:
5e173e9f
JMM
188 return ipa_compare(v1.val.ip, v2.val.ip);
189 case T_NET:
190 return net_compare(v1.val.net, v2.val.net);
e29fa06e
OZ
191 case T_STRING:
192 return strcmp(v1.val.s, v2.val.s);
3076b5ae
MM
193 default:
194 return CMP_ERROR;
38506f71
PM
195 }
196}
197
28a10f84 198static int
122deb6d 199pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
dfd48621 200{
28a10f84
OZ
201 while (m1 && m2)
202 {
122deb6d 203 if (m1->kind != m2->kind)
28a10f84
OZ
204 return 0;
205
122deb6d
OZ
206 if (m1->kind == PM_ASN_EXPR)
207 {
208 if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
209 return 0;
210 }
211 else
212 {
213 if ((m1->val != m2->val) || (m1->val2 != m2->val2))
214 return 0;
215 }
216
28a10f84
OZ
217 m1 = m1->next;
218 m2 = m2->next;
219 }
220
33d22f0e 221 return !m1 && !m2;
28a10f84
OZ
222}
223
224/**
225 * val_same - compare two values
226 * @v1: first value
227 * @v2: second value
228 *
229 * Compares two values and returns 1 if they are same and 0 if not.
230 * Comparison of values of different types is valid and returns 0.
231 */
232int
233val_same(struct f_val v1, struct f_val v2)
dfd48621 234{
28a10f84
OZ
235 int rc;
236
237 rc = val_compare(v1, v2);
238 if (rc != CMP_ERROR)
239 return !rc;
240
241 if (v1.type != v2.type)
242 return 0;
243
244 switch (v1.type) {
245 case T_PATH_MASK:
122deb6d 246 return pm_same(v1.val.path_mask, v2.val.path_mask);
28a10f84
OZ
247 case T_PATH:
248 case T_CLIST:
249 case T_ECLIST:
66dbdbd9 250 case T_LCLIST:
28a10f84
OZ
251 return adata_same(v1.val.ad, v2.val.ad);
252 case T_SET:
253 return same_tree(v1.val.t, v2.val.t);
254 case T_PREFIX_SET:
255 return trie_same(v1.val.ti, v2.val.ti);
256 default:
257 bug("Invalid type in val_same(): %x", v1.type);
258 }
dfd48621 259}
b1a597e0 260
ba5c0057
OZ
261static int
262clist_set_type(struct f_tree *set, struct f_val *v)
263{
e92a4b85
OZ
264 switch (set->from.type)
265 {
ba5c0057
OZ
266 case T_PAIR:
267 v->type = T_PAIR;
268 return 1;
e92a4b85 269
ba5c0057 270 case T_QUAD:
ba5c0057
OZ
271 v->type = T_QUAD;
272 return 1;
e92a4b85
OZ
273
274 case T_IP:
275 if (val_is_ip4(set->from) && val_is_ip4(set->to))
276 {
277 v->type = T_QUAD;
278 return 1;
279 }
280 /* Fall through */
ba5c0057
OZ
281 default:
282 v->type = T_VOID;
283 return 0;
284 }
285}
286
42a0c054
OZ
287static inline int
288eclist_set_type(struct f_tree *set)
289{ return set->from.type == T_EC; }
290
66dbdbd9
OZ
291static inline int
292lclist_set_type(struct f_tree *set)
293{ return set->from.type == T_LC; }
294
ba5c0057
OZ
295static int
296clist_match_set(struct adata *clist, struct f_tree *set)
297{
298 if (!clist)
299 return 0;
300
301 struct f_val v;
302 if (!clist_set_type(set, &v))
303 return CMP_ERROR;
304
305 u32 *l = (u32 *) clist->data;
306 u32 *end = l + clist->length/4;
42a0c054 307
ba5c0057
OZ
308 while (l < end) {
309 v.val.i = *l++;
310 if (find_tree(set, v))
311 return 1;
312 }
313 return 0;
314}
315
42a0c054
OZ
316static int
317eclist_match_set(struct adata *list, struct f_tree *set)
318{
319 if (!list)
320 return 0;
321
322 if (!eclist_set_type(set))
323 return CMP_ERROR;
324
325 struct f_val v;
326 u32 *l = int_set_get_data(list);
327 int len = int_set_get_size(list);
328 int i;
329
330 v.type = T_EC;
331 for (i = 0; i < len; i += 2) {
332 v.val.ec = ec_get(l, i);
333 if (find_tree(set, v))
334 return 1;
335 }
336
337 return 0;
338}
339
66dbdbd9
OZ
340static int
341lclist_match_set(struct adata *list, struct f_tree *set)
342{
343 if (!list)
344 return 0;
345
346 if (!lclist_set_type(set))
347 return CMP_ERROR;
348
349 struct f_val v;
350 u32 *l = int_set_get_data(list);
351 int len = int_set_get_size(list);
352 int i;
353
354 v.type = T_LC;
355 for (i = 0; i < len; i += 3) {
356 v.val.lc = lc_get(l, i);
357 if (find_tree(set, v))
358 return 1;
359 }
360
361 return 0;
362}
363
ba5c0057 364static struct adata *
0888a737 365clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
ba5c0057 366{
0888a737 367 if (!list)
ba5c0057
OZ
368 return NULL;
369
0888a737 370 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
ba5c0057 371 struct f_val v;
0888a737
OZ
372 if (tree)
373 clist_set_type(set.val.t, &v);
374 else
375 v.type = T_PAIR;
ba5c0057 376
0888a737
OZ
377 int len = int_set_get_size(list);
378 u32 *l = int_set_get_data(list);
379 u32 tmp[len];
ba5c0057 380 u32 *k = tmp;
0888a737 381 u32 *end = l + len;
ba5c0057
OZ
382
383 while (l < end) {
384 v.val.i = *l++;
0888a737
OZ
385 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
386 if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
ba5c0057
OZ
387 *k++ = v.val.i;
388 }
389
3e236955 390 uint nl = (k - tmp) * sizeof(u32);
0888a737
OZ
391 if (nl == list->length)
392 return list;
ba5c0057 393
42a0c054
OZ
394 struct adata *res = adata_empty(pool, nl);
395 memcpy(res->data, tmp, nl);
396 return res;
397}
398
399static struct adata *
0888a737 400eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
42a0c054
OZ
401{
402 if (!list)
403 return NULL;
404
0888a737 405 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
42a0c054
OZ
406 struct f_val v;
407
408 int len = int_set_get_size(list);
409 u32 *l = int_set_get_data(list);
410 u32 tmp[len];
411 u32 *k = tmp;
412 int i;
413
414 v.type = T_EC;
415 for (i = 0; i < len; i += 2) {
416 v.val.ec = ec_get(l, i);
0888a737
OZ
417 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
418 if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
42a0c054
OZ
419 *k++ = l[i];
420 *k++ = l[i+1];
421 }
422 }
423
3e236955 424 uint nl = (k - tmp) * sizeof(u32);
42a0c054
OZ
425 if (nl == list->length)
426 return list;
427
428 struct adata *res = adata_empty(pool, nl);
ba5c0057
OZ
429 memcpy(res->data, tmp, nl);
430 return res;
431}
432
66dbdbd9
OZ
433static struct adata *
434lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
435{
436 if (!list)
437 return NULL;
438
439 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
440 struct f_val v;
441
442 int len = int_set_get_size(list);
443 u32 *l = int_set_get_data(list);
444 u32 tmp[len];
445 u32 *k = tmp;
446 int i;
447
448 v.type = T_LC;
449 for (i = 0; i < len; i += 3) {
450 v.val.lc = lc_get(l, i);
451 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
452 if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
453 k = lc_copy(k, l+i);
454 }
455
3e236955 456 uint nl = (k - tmp) * sizeof(u32);
42a0c054
OZ
457 if (nl == list->length)
458 return list;
459
460 struct adata *res = adata_empty(pool, nl);
ba5c0057
OZ
461 memcpy(res->data, tmp, nl);
462 return res;
463}
464
8dcf2544 465/**
3e82b32d 466 * val_in_range - implement |~| operator
8dcf2544
PM
467 * @v1: element
468 * @v2: set
469 *
b655596d 470 * Checks if @v1 is element (|~| operator) of @v2.
b093c328 471 */
9831e591 472static int
7db7b7db
PM
473val_in_range(struct f_val v1, struct f_val v2)
474{
b655596d
OZ
475 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
476 return as_path_match(v1.val.ad, v2.val.path_mask);
6dc7a0cb 477
b655596d 478 if ((v1.type == T_INT) && (v2.type == T_PATH))
a15dab76 479 return as_path_contains(v2.val.ad, v1.val.i, 1);
6dc7a0cb 480
b655596d
OZ
481 if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
482 return int_set_contains(v2.val.ad, v1.val.i);
b655596d 483 /* IP->Quad implicit conversion */
5e173e9f
JMM
484 if (val_is_ip4(v1) && (v2.type == T_CLIST))
485 return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
b1a597e0 486
b655596d
OZ
487 if ((v1.type == T_EC) && (v2.type == T_ECLIST))
488 return ec_set_contains(v2.val.ad, v1.val.ec);
ba5c0057 489
66dbdbd9
OZ
490 if ((v1.type == T_LC) && (v2.type == T_LCLIST))
491 return lc_set_contains(v2.val.ad, v1.val.lc);
492
b655596d
OZ
493 if ((v1.type == T_STRING) && (v2.type == T_STRING))
494 return patmatch(v2.val.s, v1.val.s);
42a0c054 495
5e173e9f
JMM
496 if ((v1.type == T_IP) && (v2.type == T_NET))
497 return ipa_in_netX(v1.val.ip, v2.val.net);
7db7b7db 498
5e173e9f
JMM
499 if ((v1.type == T_NET) && (v2.type == T_NET))
500 return net_in_netX(v1.val.net, v2.val.net);
0d1b3c4c 501
5e173e9f
JMM
502 if ((v1.type == T_NET) && (v2.type == T_PREFIX_SET))
503 return trie_match_net(v2.val.ti, v1.val.net);
0d1b3c4c 504
b655596d
OZ
505 if (v2.type != T_SET)
506 return CMP_ERROR;
0d1b3c4c 507
b655596d
OZ
508 /* With integrated Quad<->IP implicit conversion */
509 if ((v1.type == v2.val.t->from.type) ||
e92a4b85 510 ((v1.type == T_QUAD) && val_is_ip4(v2.val.t->from) && val_is_ip4(v2.val.t->to)))
b655596d 511 return !!find_tree(v2.val.t, v1);
0d1b3c4c 512
b655596d 513 if (v1.type == T_CLIST)
ba5c0057 514 return clist_match_set(v1.val.ad, v2.val.t);
0d1b3c4c 515
b655596d 516 if (v1.type == T_ECLIST)
42a0c054
OZ
517 return eclist_match_set(v1.val.ad, v2.val.t);
518
66dbdbd9
OZ
519 if (v1.type == T_LCLIST)
520 return lclist_match_set(v1.val.ad, v2.val.t);
521
b655596d 522 if (v1.type == T_PATH)
cc31b75a
OZ
523 return as_path_match_set(v1.val.ad, v2.val.t);
524
7db7b7db 525 return CMP_ERROR;
38506f71
PM
526}
527
4c5f93d7 528/*
0e175f9f 529 * val_format - format filter value
b093c328 530 */
508d9360 531void
0e175f9f 532val_format(struct f_val v, buffer *buf)
38506f71 533{
ecd25633 534 char buf2[1024];
0e175f9f
OZ
535 switch (v.type)
536 {
537 case T_VOID: buffer_puts(buf, "(void)"); return;
538 case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
52e030e1 539 case T_INT: buffer_print(buf, "%u", v.val.i); return;
0e175f9f 540 case T_STRING: buffer_print(buf, "%s", v.val.s); return;
5e173e9f
JMM
541 case T_IP: buffer_print(buf, "%I", v.val.ip); return;
542 case T_NET: buffer_print(buf, "%N", v.val.net); return;
52e030e1 543 case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
0e175f9f
OZ
544 case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
545 case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
66dbdbd9 546 case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
8c9986d3 547 case T_RD: rd_format(v.val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
0e175f9f
OZ
548 case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
549 case T_SET: tree_format(v.val.t, buf); return;
52e030e1 550 case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
0e175f9f
OZ
551 case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
552 case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
553 case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
66dbdbd9 554 case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
0e175f9f
OZ
555 case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
556 default: buffer_print(buf, "[unknown type %x]", v.type); return;
38506f71 557 }
38506f71
PM
558}
559
36bbfc70 560
a946317f 561static inline void f_cache_eattrs(struct filter_state *fs)
13c0be19 562{
a946317f 563 fs->eattrs = &((*fs->rte)->attrs->eattrs);
13c0be19
JMM
564}
565
a946317f 566static inline void f_rte_cow(struct filter_state *fs)
a03ede64 567{
a946317f 568 if (!((*fs->rte)->flags & REF_COW))
13c0be19
JMM
569 return;
570
a946317f 571 *fs->rte = rte_cow(*fs->rte);
a03ede64
OZ
572}
573
4c5f93d7 574/*
b093c328
PM
575 * rta_cow - prepare rta for modification by filter
576 */
9831e591 577static void
a946317f 578f_rta_cow(struct filter_state *fs)
26c09e1d 579{
a946317f 580 if (!rta_is_cached((*fs->rte)->attrs))
8d9eef17
OZ
581 return;
582
583 /* Prepare to modify rte */
a946317f 584 f_rte_cow(fs);
8d9eef17
OZ
585
586 /* Store old rta to free it later, it stores reference from rte_cow() */
a946317f 587 fs->old_rta = (*fs->rte)->attrs;
8d9eef17
OZ
588
589 /*
590 * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
a946317f 591 * with fs->old_rta (they will be copied when the cached rta will be obtained
8d9eef17
OZ
592 * at the end of f_run()), also the lock of hostentry is inherited (we
593 * suppose hostentry is not changed by filters).
594 */
a946317f 595 (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool);
13c0be19
JMM
596
597 /* Re-cache the ea_list */
a946317f 598 f_cache_eattrs(fs);
26c09e1d
PM
599}
600
4b135d09 601static char *
a946317f 602val_format_str(struct filter_state *fs, struct f_val v) {
4b135d09
PT
603 buffer b;
604 LOG_BUFFER_INIT(b);
605 val_format(v, &b);
a946317f 606 return lp_strdup(fs->pool, b.start);
4b135d09
PT
607}
608
1123e707 609static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
cb530392 610
b093c328
PM
611/**
612 * interpret
a946317f 613 * @fs: filter state
2e9b2421 614 * @what: filter to interpret
b093c328 615 *
4c5f93d7 616 * Interpret given tree of filter instructions. This is core function
b093c328 617 * of filter system and does all the hard work.
771ae456
PM
618 *
619 * Each instruction has 4 fields: code (which is instruction code),
620 * aux (which is extension to instruction code, typically type),
621 * arg1 and arg2 - arguments. Depending on instruction, arguments
315f23a0 622 * are either integers, or pointers to instruction trees. Common
771ae456
PM
623 * instructions like +, that have two expressions as arguments use
624 * TWOARGS macro to get both of them evaluated.
b093c328 625 */
7afa1438 626static enum filter_return
fc8df41e 627interpret(struct filter_state *fs, struct f_inst *what)
23b1539b
PM
628{
629 struct symbol *sym;
fc8df41e 630 struct f_val *vp;
92a72a4c 631 unsigned u1, u2;
7afa1438 632 enum filter_return fret;
6a57bb31 633 int i;
7ea5b00f 634 u32 as;
23b1539b 635
fc8df41e 636#define res fs->stack[fs->stack_ptr].val
8e8b1fe4 637#define v0 res
fc8df41e
JMM
638#define v1 fs->stack[fs->stack_ptr + 1].val
639#define v2 fs->stack[fs->stack_ptr + 2].val
640#define v3 fs->stack[fs->stack_ptr + 3].val
641
642 res = (struct f_val) { .type = T_VOID };
7afa1438 643
7c601e6b 644 for ( ; what; what = what->next) {
a8740d6c
MM
645 res = (struct f_val) { .type = T_VOID };
646 switch (what->fi_code) {
7afa1438 647
aca82639 648#define runtime(fmt, ...) do { \
a8740d6c
MM
649 if (!(fs->flags & FF_SILENT)) \
650 log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
651 return F_ERROR; \
652} while(0)
aca82639 653
7f0ac737 654#define ARG_ANY_T(n, tt) INTERPRET(what->a[n-1].p, tt)
8e8b1fe4 655#define ARG_ANY(n) ARG_ANY_T(n, n)
aca82639 656
8e8b1fe4
MM
657#define ARG_T(n,tt,t) do { \
658 ARG_ANY_T(n,tt); \
659 if (v##tt.type != t) \
a8740d6c 660 runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
8e8b1fe4 661 n, f_instruction_name(what->fi_code), t, v##tt.type); \
a8740d6c 662} while (0)
aca82639 663
8e8b1fe4
MM
664#define ARG(n,t) ARG_T(n,n,t)
665
fc8df41e 666#define INTERPRET(what_, n) do { \
a8740d6c
MM
667 fs->stack_ptr += n; \
668 fret = interpret(fs, what_); \
669 fs->stack_ptr -= n; \
670 if (fret == F_RETURN) \
671 bug("This shall not happen"); \
672 if (fret > F_RETURN) \
673 return fret; \
fc8df41e 674} while (0)
aca82639 675
a8740d6c 676#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
aca82639 677
a8740d6c 678#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
aca82639 679
7f0ac737 680#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i))
25566c68 681
967b88d9
MM
682 case FI_NOP:
683 bug("This shall not happen");
684
685#include "filter/f-inst-interpret.c"
686
687 break;
688 default:
689 bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
aca82639 690
7afa1438 691#undef res
aca82639
JMM
692#undef runtime
693#undef ARG_ANY
694#undef ARG
695#undef INTERPRET
696#undef ACCESS_RTE
697#undef ACCESS_EATTRS
a8740d6c
MM
698 }
699 }
7afa1438 700 return F_NOP;
23b1539b
PM
701}
702
0ec6b5ec
JMM
703
704#define ARG(n) \
7f0ac737 705 if (!i_same(f1->a[n-1].p, f2->a[n-1].p)) \
9a4037d4
PM
706 return 0;
707
0ec6b5ec
JMM
708#define ONEARG ARG(1);
709#define TWOARGS ONEARG; ARG(2);
710#define THREEARGS TWOARGS; ARG(3);
9a4037d4 711
7f0ac737 712#define A2_SAME if (f1->a[1].i != f2->a[1].i) return 0;
9a4037d4 713
4c5f93d7 714/*
b093c328
PM
715 * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
716 */
9a4037d4
PM
717int
718i_same(struct f_inst *f1, struct f_inst *f2)
719{
9a4037d4
PM
720 if ((!!f1) != (!!f2))
721 return 0;
d4d75628
PM
722 if (!f1)
723 return 1;
9a4037d4
PM
724 if (f1->aux != f2->aux)
725 return 0;
5a14df39 726 if (f1->fi_code != f2->fi_code)
9a4037d4 727 return 0;
d4d75628
PM
728 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
729 return 1;
9a4037d4 730
5a14df39 731 switch(f1->fi_code) {
74bfd2f9 732 case FI_ADD: /* fall through */
5a14df39
MJM
733 case FI_SUBTRACT:
734 case FI_MULTIPLY:
735 case FI_DIVIDE:
736 case FI_OR:
737 case FI_AND:
738 case FI_PAIR_CONSTRUCT:
739 case FI_EC_CONSTRUCT:
740 case FI_NEQ:
741 case FI_EQ:
742 case FI_LT:
743 case FI_LTE: TWOARGS; break;
744
7f0ac737 745 case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a[0].p, f2->a[0].p)) return 0; break;
e8bc64e3 746
5a14df39
MJM
747 case FI_NOT: ONEARG; break;
748 case FI_NOT_MATCH:
749 case FI_MATCH: TWOARGS; break;
750 case FI_DEFINED: ONEARG; break;
d1ba927b 751 case FI_TYPE: ONEARG; break;
5a14df39
MJM
752
753 case FI_LC_CONSTRUCT:
478f9bab 754 THREEARGS;
66dbdbd9
OZ
755 break;
756
5a14df39 757 case FI_SET:
0ec6b5ec 758 ARG(2);
9a4037d4
PM
759 {
760 struct symbol *s1, *s2;
7f0ac737
MM
761 s1 = f1->a[0].p;
762 s2 = f2->a[0].p;
9a4037d4
PM
763 if (strcmp(s1->name, s2->name))
764 return 0;
765 if (s1->class != s2->class)
766 return 0;
767 }
768 break;
769
5a14df39 770 case FI_CONSTANT:
b1a597e0
OZ
771 switch (f1->aux) {
772
773 case T_PREFIX_SET:
7f0ac737 774 if (!trie_same(f1->a[1].p, f2->a[1].p))
b1a597e0 775 return 0;
9be1086d 776 break;
b1a597e0
OZ
777
778 case T_SET:
7f0ac737 779 if (!same_tree(f1->a[1].p, f2->a[1].p))
4bb18dd2 780 return 0;
9be1086d 781 break;
b1a597e0 782
4bb18dd2 783 case T_STRING:
7f0ac737 784 if (strcmp(f1->a[1].p, f2->a[1].p))
4bb18dd2
PM
785 return 0;
786 break;
b1a597e0 787
4bb18dd2
PM
788 default:
789 A2_SAME;
790 }
791 break;
507e182a 792
5a14df39 793 case FI_CONSTANT_INDIRECT:
7f0ac737 794 if (!val_same(* (struct f_val *) f1->a[0].p, * (struct f_val *) f2->a[0].p))
9a4037d4
PM
795 return 0;
796 break;
28a10f84 797
5a14df39 798 case FI_VARIABLE:
7f0ac737 799 if (strcmp((char *) f1->a[1].p, (char *) f2->a[1].p))
9be1086d
OF
800 return 0;
801 break;
5a14df39 802 case FI_PRINT: case FI_LENGTH: ONEARG; break;
224b77d4 803 case FI_CONDITION: THREEARGS; break;
5a14df39
MJM
804 case FI_NOP: case FI_EMPTY: break;
805 case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
806 case FI_PREF_GET:
807 case FI_RTA_GET: A2_SAME; break;
808 case FI_EA_GET: A2_SAME; break;
809 case FI_PREF_SET:
810 case FI_RTA_SET:
811 case FI_EA_SET: ONEARG; A2_SAME; break;
812
813 case FI_RETURN: ONEARG; break;
823ad121
JMM
814 case FI_ROA_MAXLEN: ONEARG; break;
815 case FI_ROA_ASN: ONEARG; break;
b24b7811 816 case FI_SADR_SRC: ONEARG; break;
5a14df39 817 case FI_IP: ONEARG; break;
823ad121 818 case FI_IS_V4: ONEARG; break;
d1ba927b 819 case FI_ROUTE_DISTINGUISHER: ONEARG; break;
5a14df39 820 case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
315f23a0 821 ONEARG;
7f0ac737 822 if (!i_same(f1->a[1].p, f2->a[1].p))
315f23a0 823 return 0;
7f0ac737 824 f2->a[1].p = f1->a[1].p;
d4d75628 825 break;
5a14df39 826 case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
7f0ac737 827 case FI_SWITCH: ONEARG; if (!same_tree(f1->a[1].p, f2->a[1].p)) return 0; break;
5a14df39
MJM
828 case FI_IP_MASK: TWOARGS; break;
829 case FI_PATH_PREPEND: TWOARGS; break;
830 case FI_CLIST_ADD_DEL: TWOARGS; break;
831 case FI_AS_PATH_FIRST:
832 case FI_AS_PATH_LAST:
833 case FI_AS_PATH_LAST_NAG: ONEARG; break;
834 case FI_ROA_CHECK:
af582c48 835 TWOARGS;
84360407
MM
836 /* FIXME: ROA check results may change anyway */
837 if (strcmp(f1->a[2].rtc->name,
838 f2->a[2].rtc->name))
af582c48
OZ
839 return 0;
840 break;
823ad121
JMM
841 case FI_FORMAT: ONEARG; break;
842 case FI_ASSERT: ONEARG; break;
9a4037d4 843 default:
5a14df39 844 bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
9a4037d4
PM
845 }
846 return i_same(f1->next, f2->next);
847}
848
ff95080f 849/**
a03ede64
OZ
850 * f_run - run a filter for a route
851 * @filter: filter to run
852 * @rte: route being filtered, may be modified
ff95080f 853 * @tmp_pool: all filter allocations go from this pool
4c5f93d7 854 * @flags: flags
a03ede64
OZ
855 *
856 * If filter needs to modify the route, there are several
857 * posibilities. @rte might be read-only (with REF_COW flag), in that
858 * case rw copy is obtained by rte_cow() and @rte is replaced. If
859 * @rte is originally rw, it may be directly modified (and it is never
860 * copied).
861 *
862 * The returned rte may reuse the (possibly cached, cloned) rta, or
863 * (if rta was modificied) contains a modified uncached rta, which
864 * uses parts allocated from @tmp_pool and parts shared from original
865 * rta. There is one exception - if @rte is rw but contains a cached
866 * rta and that is modified, rta in returned rte is also cached.
867 *
868 * Ownership of cached rtas is consistent with rte, i.e.
869 * if a new rte is returned, it has its own clone of cached rta
870 * (and cached rta of read-only source rte is intact), if rte is
871 * modified in place, old cached rta is possibly freed.
ff95080f 872 */
7afa1438 873enum filter_return
13c0be19 874f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
23b1539b 875{
36da2857
OZ
876 if (filter == FILTER_ACCEPT)
877 return F_ACCEPT;
878
879 if (filter == FILTER_REJECT)
880 return F_REJECT;
881
a03ede64 882 int rte_cow = ((*rte)->flags & REF_COW);
6b9fa320 883 DBG( "Running filter `%s'...", filter->name );
23b1539b 884
a946317f
JMM
885 struct filter_state fs = {
886 .rte = rte,
887 .pool = tmp_pool,
888 .flags = flags,
fc8df41e 889 .stack = filter_stack,
a946317f 890 };
0d1b3c4c 891
a946317f 892 LOG_BUFFER_INIT(fs.buf);
0e175f9f 893
fc8df41e 894 enum filter_return fret = interpret(&fs, filter->root);
a03ede64 895
a946317f 896 if (fs.old_rta) {
a03ede64 897 /*
a946317f 898 * Cached rta was modified and fs->rte contains now an uncached one,
a03ede64 899 * sharing some part with the cached one. The cached rta should
a946317f 900 * be freed (if rte was originally COW, fs->old_rta is a clone
a03ede64
OZ
901 * obtained during rte_cow()).
902 *
903 * This also implements the exception mentioned in f_run()
904 * description. The reason for this is that rta reuses parts of
a946317f 905 * fs->old_rta, and these may be freed during rta_free(fs->old_rta).
a03ede64
OZ
906 * This is not the problem if rte was COW, because original rte
907 * also holds the same rta.
908 */
909 if (!rte_cow)
a946317f 910 (*fs.rte)->attrs = rta_lookup((*fs.rte)->attrs);
a03ede64 911
a946317f 912 rta_free(fs.old_rta);
a03ede64
OZ
913 }
914
0d1b3c4c 915
7afa1438 916 if (fret < F_ACCEPT) {
a946317f 917 if (!(fs.flags & FF_SILENT))
b9405791 918 log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
23b1539b 919 return F_ERROR;
0b1cad81 920 }
52e030e1 921 DBG( "done (%u)\n", res.val.i );
7afa1438 922 return fret;
23b1539b
PM
923}
924
1321e12a
OZ
925/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
926
7afa1438 927enum filter_return
1321e12a
OZ
928f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
929{
1321e12a 930
a946317f
JMM
931 struct filter_state fs = {
932 .rte = rte,
933 .pool = tmp_pool,
fc8df41e 934 .stack = filter_stack,
a946317f 935 };
1321e12a 936
a946317f 937 LOG_BUFFER_INIT(fs.buf);
1321e12a
OZ
938
939 /* Note that in this function we assume that rte->attrs is private / uncached */
fc8df41e 940 return interpret(&fs, expr);
1321e12a
OZ
941}
942
7afa1438
JMM
943enum filter_return
944f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres)
1c20608e 945{
a946317f
JMM
946 struct filter_state fs = {
947 .pool = tmp_pool,
fc8df41e 948 .stack = filter_stack,
a946317f 949 };
0d1b3c4c 950
a946317f 951 LOG_BUFFER_INIT(fs.buf);
0e175f9f 952
fc8df41e
JMM
953 enum filter_return fret = interpret(&fs, expr);
954 *pres = filter_stack[0].val;
955 return fret;
508d9360 956}
0d1b3c4c 957
52e030e1 958uint
508d9360
OZ
959f_eval_int(struct f_inst *expr)
960{
961 /* Called independently in parse-time to eval expressions */
fc8df41e
JMM
962 struct filter_state fs = {
963 .pool = cfg_mem,
964 .stack = filter_stack,
965 };
966
967 LOG_BUFFER_INIT(fs.buf);
968
969 if (interpret(&fs, expr) > F_RETURN)
7afa1438 970 cf_error("Runtime error while evaluating expression");
0d1b3c4c 971
fc8df41e 972 if (filter_stack[0].val.type != T_INT)
b1c9d871 973 cf_error("Integer expression expected");
508d9360 974
fc8df41e 975 return filter_stack[0].val.val.i;
b1c9d871 976}
1c20608e 977
ff95080f
PM
978/**
979 * filter_same - compare two filters
980 * @new: first filter to be compared
981 * @old: second filter to be compared, notice that this filter is
982 * damaged while comparing.
983 *
984 * Returns 1 in case filters are same, otherwise 0. If there are
985 * underlying bugs, it will rather say 0 on same filters than say
986 * 1 on different.
987 */
30a6108c
MM
988int
989filter_same(struct filter *new, struct filter *old)
990{
81ce667b
MM
991 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
992 return 1;
993 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
994 new == FILTER_ACCEPT || new == FILTER_REJECT)
995 return 0;
9a4037d4 996 return i_same(new->root, old->root);
30a6108c 997}