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