]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Filter: Fixed bugs in FI_CALL and FI_SWITCH
[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"
8bdb05ed 50#include "filter/f-inst.h"
4f082dfa 51#include "filter/data.h"
23b1539b 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 64
a946317f 65static inline void f_cache_eattrs(struct filter_state *fs)
13c0be19 66{
a946317f 67 fs->eattrs = &((*fs->rte)->attrs->eattrs);
13c0be19
JMM
68}
69
a946317f 70static inline void f_rte_cow(struct filter_state *fs)
a03ede64 71{
a946317f 72 if (!((*fs->rte)->flags & REF_COW))
13c0be19
JMM
73 return;
74
a946317f 75 *fs->rte = rte_cow(*fs->rte);
a03ede64
OZ
76}
77
4c5f93d7 78/*
b093c328
PM
79 * rta_cow - prepare rta for modification by filter
80 */
9831e591 81static void
a946317f 82f_rta_cow(struct filter_state *fs)
26c09e1d 83{
a946317f 84 if (!rta_is_cached((*fs->rte)->attrs))
8d9eef17
OZ
85 return;
86
87 /* Prepare to modify rte */
a946317f 88 f_rte_cow(fs);
8d9eef17
OZ
89
90 /* Store old rta to free it later, it stores reference from rte_cow() */
a946317f 91 fs->old_rta = (*fs->rte)->attrs;
8d9eef17
OZ
92
93 /*
94 * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
a946317f 95 * with fs->old_rta (they will be copied when the cached rta will be obtained
8d9eef17
OZ
96 * at the end of f_run()), also the lock of hostentry is inherited (we
97 * suppose hostentry is not changed by filters).
98 */
a946317f 99 (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool);
13c0be19
JMM
100
101 /* Re-cache the ea_list */
a946317f 102 f_cache_eattrs(fs);
26c09e1d
PM
103}
104
4b135d09 105static char *
4c553c5a 106val_format_str(struct filter_state *fs, struct f_val *v) {
4b135d09
PT
107 buffer b;
108 LOG_BUFFER_INIT(b);
109 val_format(v, &b);
a946317f 110 return lp_strdup(fs->pool, b.start);
4b135d09
PT
111}
112
1123e707 113static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
cb530392 114
b093c328
PM
115/**
116 * interpret
a946317f 117 * @fs: filter state
2e9b2421 118 * @what: filter to interpret
b093c328 119 *
4c5f93d7 120 * Interpret given tree of filter instructions. This is core function
b093c328 121 * of filter system and does all the hard work.
771ae456
PM
122 *
123 * Each instruction has 4 fields: code (which is instruction code),
124 * aux (which is extension to instruction code, typically type),
125 * arg1 and arg2 - arguments. Depending on instruction, arguments
315f23a0 126 * are either integers, or pointers to instruction trees. Common
771ae456
PM
127 * instructions like +, that have two expressions as arguments use
128 * TWOARGS macro to get both of them evaluated.
b093c328 129 */
7afa1438 130static enum filter_return
4c553c5a 131interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
23b1539b 132{
8bdb05ed
MM
133
134#define F_VAL_STACK_MAX 4096
135 /* Value stack for execution */
136 struct f_val_stack {
137 uint cnt; /* Current stack size; 0 for empty */
138 struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */
139 } vstk;
140
141 /* The stack itself is intentionally kept as-is for performance reasons.
142 * Do NOT rewrite this to initialization by struct literal. It's slow.
143 */
4c553c5a 144 vstk.cnt = 0;
8bdb05ed
MM
145#define F_EXEC_STACK_MAX 4096
146
147 /* Exception bits */
148 enum f_exception {
149 FE_RETURN = 0x1,
150 };
23b1539b 151
8bdb05ed
MM
152 /* Instruction stack for execution */
153 struct f_exec_stack {
154 struct {
155 const struct f_line *line; /* The line that is being executed */
156 uint pos; /* Instruction index in the line */
157 uint ventry; /* Value stack depth on entry */
158 enum f_exception emask; /* Exception mask */
159 } item[F_EXEC_STACK_MAX];
160 uint cnt; /* Current stack size; 0 for empty */
161 } estk;
162
163 /* The same as with the value stack. Not resetting the stack for performance reasons. */
4c553c5a 164 estk.cnt = 1;
8bdb05ed 165 estk.item[0].line = line;
4c553c5a 166 estk.item[0].pos = 0;
fc8df41e 167
4c553c5a
MM
168#define curline estk.item[estk.cnt-1]
169
ea4f55e3
MM
170#if DEBUGGING
171 debug("Interpreting line.");
172 f_dump_line(line, 1);
173#endif
174
4c553c5a
MM
175 while (estk.cnt > 0) {
176 while (curline.pos < curline.line->len) {
177 const struct f_line_item *what = &(curline.line->items[curline.pos++]);
7afa1438 178
4c553c5a
MM
179
180 switch (what->fi_code) {
181#define res vstk.val[vstk.cnt]
182#define v1 vstk.val[vstk.cnt]
183#define v2 vstk.val[vstk.cnt + 1]
184#define v3 vstk.val[vstk.cnt + 2]
7afa1438 185
aca82639 186#define runtime(fmt, ...) do { \
a8740d6c
MM
187 if (!(fs->flags & FF_SILENT)) \
188 log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
189 return F_ERROR; \
190} while(0)
aca82639 191
a8740d6c 192#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
a8740d6c 193#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
aca82639 194
967b88d9 195#include "filter/f-inst-interpret.c"
7afa1438 196#undef res
4c553c5a
MM
197#undef v1
198#undef v2
199#undef v3
aca82639 200#undef runtime
aca82639
JMM
201#undef ACCESS_RTE
202#undef ACCESS_EATTRS
4c553c5a 203 }
a8740d6c 204 }
4c553c5a 205 estk.cnt--;
a8740d6c 206 }
23b1539b 207
4c553c5a
MM
208 switch (vstk.cnt) {
209 case 0:
210 if (val) {
211 log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack");
212 return F_ERROR;
213 }
214 return F_NOP;
215 case 1:
216 if (val) {
217 *val = vstk.val[0];
218 return F_NOP;
219 }
220 /* fallthrough */
221 default:
222 log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt);
223 return F_ERROR;
224 }
225}
0ec6b5ec 226
9a4037d4 227
ff95080f 228/**
a03ede64
OZ
229 * f_run - run a filter for a route
230 * @filter: filter to run
231 * @rte: route being filtered, may be modified
ff95080f 232 * @tmp_pool: all filter allocations go from this pool
4c5f93d7 233 * @flags: flags
a03ede64
OZ
234 *
235 * If filter needs to modify the route, there are several
236 * posibilities. @rte might be read-only (with REF_COW flag), in that
237 * case rw copy is obtained by rte_cow() and @rte is replaced. If
238 * @rte is originally rw, it may be directly modified (and it is never
239 * copied).
240 *
241 * The returned rte may reuse the (possibly cached, cloned) rta, or
242 * (if rta was modificied) contains a modified uncached rta, which
243 * uses parts allocated from @tmp_pool and parts shared from original
244 * rta. There is one exception - if @rte is rw but contains a cached
245 * rta and that is modified, rta in returned rte is also cached.
246 *
247 * Ownership of cached rtas is consistent with rte, i.e.
248 * if a new rte is returned, it has its own clone of cached rta
249 * (and cached rta of read-only source rte is intact), if rte is
250 * modified in place, old cached rta is possibly freed.
ff95080f 251 */
7afa1438 252enum filter_return
4c553c5a 253f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
23b1539b 254{
36da2857
OZ
255 if (filter == FILTER_ACCEPT)
256 return F_ACCEPT;
257
258 if (filter == FILTER_REJECT)
259 return F_REJECT;
260
a03ede64 261 int rte_cow = ((*rte)->flags & REF_COW);
6b9fa320 262 DBG( "Running filter `%s'...", filter->name );
23b1539b 263
a946317f
JMM
264 struct filter_state fs = {
265 .rte = rte,
266 .pool = tmp_pool,
267 .flags = flags,
268 };
0d1b3c4c 269
a946317f 270 LOG_BUFFER_INIT(fs.buf);
0e175f9f 271
4c553c5a 272 enum filter_return fret = interpret(&fs, filter->root, NULL);
a03ede64 273
a946317f 274 if (fs.old_rta) {
a03ede64 275 /*
a946317f 276 * Cached rta was modified and fs->rte contains now an uncached one,
a03ede64 277 * sharing some part with the cached one. The cached rta should
a946317f 278 * be freed (if rte was originally COW, fs->old_rta is a clone
a03ede64
OZ
279 * obtained during rte_cow()).
280 *
281 * This also implements the exception mentioned in f_run()
282 * description. The reason for this is that rta reuses parts of
a946317f 283 * fs->old_rta, and these may be freed during rta_free(fs->old_rta).
a03ede64
OZ
284 * This is not the problem if rte was COW, because original rte
285 * also holds the same rta.
286 */
287 if (!rte_cow)
a946317f 288 (*fs.rte)->attrs = rta_lookup((*fs.rte)->attrs);
a03ede64 289
a946317f 290 rta_free(fs.old_rta);
a03ede64
OZ
291 }
292
0d1b3c4c 293
7afa1438 294 if (fret < F_ACCEPT) {
a946317f 295 if (!(fs.flags & FF_SILENT))
b9405791 296 log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
23b1539b 297 return F_ERROR;
0b1cad81 298 }
52e030e1 299 DBG( "done (%u)\n", res.val.i );
7afa1438 300 return fret;
23b1539b
PM
301}
302
1321e12a
OZ
303/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
304
7afa1438 305enum filter_return
4c553c5a 306f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
1321e12a 307{
1321e12a 308
a946317f
JMM
309 struct filter_state fs = {
310 .rte = rte,
311 .pool = tmp_pool,
312 };
1321e12a 313
a946317f 314 LOG_BUFFER_INIT(fs.buf);
1321e12a
OZ
315
316 /* Note that in this function we assume that rte->attrs is private / uncached */
4c553c5a 317 return interpret(&fs, expr, NULL);
1321e12a
OZ
318}
319
7afa1438 320enum filter_return
4c553c5a 321f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
1c20608e 322{
a946317f
JMM
323 struct filter_state fs = {
324 .pool = tmp_pool,
325 };
0d1b3c4c 326
a946317f 327 LOG_BUFFER_INIT(fs.buf);
0e175f9f 328
4c553c5a 329 enum filter_return fret = interpret(&fs, expr, pres);
fc8df41e 330 return fret;
508d9360 331}
0d1b3c4c 332
52e030e1 333uint
4c553c5a 334f_eval_int(const struct f_line *expr)
508d9360
OZ
335{
336 /* Called independently in parse-time to eval expressions */
fc8df41e
JMM
337 struct filter_state fs = {
338 .pool = cfg_mem,
fc8df41e
JMM
339 };
340
4c553c5a
MM
341 struct f_val val;
342
fc8df41e
JMM
343 LOG_BUFFER_INIT(fs.buf);
344
4c553c5a 345 if (interpret(&fs, expr, &val) > F_RETURN)
7afa1438 346 cf_error("Runtime error while evaluating expression");
0d1b3c4c 347
4c553c5a 348 if (val.type != T_INT)
b1c9d871 349 cf_error("Integer expression expected");
508d9360 350
4c553c5a 351 return val.val.i;
b1c9d871 352}
1c20608e 353
52893045
MM
354enum filter_return
355f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf)
356{
357 struct f_val val;
358 enum filter_return fret = f_eval(expr, tmp_pool, &val);
359 if (fret > F_RETURN)
360 val_format(&val, buf);
361 return fret;
362}
363
ff95080f
PM
364/**
365 * filter_same - compare two filters
366 * @new: first filter to be compared
0b39b1cb 367 * @old: second filter to be compared
ff95080f
PM
368 *
369 * Returns 1 in case filters are same, otherwise 0. If there are
370 * underlying bugs, it will rather say 0 on same filters than say
371 * 1 on different.
372 */
30a6108c 373int
0b39b1cb 374filter_same(const struct filter *new, const struct filter *old)
30a6108c 375{
81ce667b
MM
376 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
377 return 1;
378 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
379 new == FILTER_ACCEPT || new == FILTER_REJECT)
380 return 0;
4c553c5a 381 return f_same(new->root, old->root);
30a6108c 382}