]>
Commit | Line | Data |
---|---|---|
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 | * |
720d911d | 8 | * Notice that pair is stored as integer: first << 16 | second |
2f702671 | 9 | * |
23b1539b PM |
10 | */ |
11 | ||
6b9fa320 MM |
12 | #undef LOCAL_DEBUG |
13 | ||
23b1539b PM |
14 | #include <stdio.h> |
15 | #include <fcntl.h> | |
16 | #include <unistd.h> | |
17 | #include <sys/signal.h> | |
18 | #include <setjmp.h> | |
19 | ||
20 | #include "nest/bird.h" | |
21 | #include "lib/lists.h" | |
22 | #include "lib/resource.h" | |
23 | #include "lib/socket.h" | |
38506f71 | 24 | #include "lib/string.h" |
23b1539b PM |
25 | #include "nest/route.h" |
26 | #include "nest/protocol.h" | |
27 | #include "nest/iface.h" | |
28 | #include "conf/conf.h" | |
29 | #include "filter/filter.h" | |
30 | ||
2d496d20 PM |
31 | #define P(a,b) ((a<<8) | b) |
32 | ||
23b1539b PM |
33 | struct f_inst *startup_func = NULL; |
34 | ||
38506f71 PM |
35 | #define CMP_ERROR 999 |
36 | ||
37 | /* Compare two values, returns -1, 0, 1 compared, ERROR 999 */ | |
38 | int | |
39 | val_compare(struct f_val v1, struct f_val v2) | |
40 | { | |
41be4444 PM |
41 | if ((v1.type == T_VOID) && (v2.type == T_VOID)) |
42 | return 0; | |
43 | if (v1.type == T_VOID) /* Hack for else */ | |
44 | return -1; | |
45 | if (v2.type == T_VOID) | |
46 | return 1; | |
47 | ||
7db7b7db PM |
48 | if (v1.type != v2.type) |
49 | return CMP_ERROR; | |
38506f71 | 50 | switch (v1.type) { |
f4536657 | 51 | case T_ENUM: |
38506f71 | 52 | case T_INT: |
d3dd620b | 53 | case T_PAIR: |
38506f71 PM |
54 | if (v1.val.i == v2.val.i) return 0; |
55 | if (v1.val.i < v2.val.i) return -1; | |
56 | return 1; | |
43fc099b | 57 | case T_IP: |
6dc7a0cb PM |
58 | case T_PREFIX: |
59 | return ipa_compare(v1.val.px.ip, v2.val.px.ip); | |
41be4444 | 60 | default: { printf( "Error comparing\n" ); return CMP_ERROR; } |
38506f71 PM |
61 | } |
62 | } | |
63 | ||
6dc7a0cb PM |
64 | int |
65 | val_simple_in_range(struct f_val v1, struct f_val v2) | |
66 | { | |
67 | if ((v1.type == T_IP) && (v2.type == T_PREFIX)) | |
68 | return !(ipa_compare(ipa_and(v2.val.px.ip, ipa_mkmask(v2.val.px.len)), ipa_and(v1.val.px.ip, ipa_mkmask(v2.val.px.len)))); | |
69 | ||
70 | if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) { | |
71 | ip_addr mask; | |
72 | if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE)) | |
73 | return CMP_ERROR; | |
74 | mask = ipa_mkmask( v2.val.px.len & LEN_MASK ); | |
75 | if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask))) | |
76 | return 0; | |
8f013d9c | 77 | |
6dc7a0cb PM |
78 | if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK))) |
79 | return 0; | |
80 | if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK))) | |
81 | return 0; | |
82 | if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16))) | |
83 | || (v1.val.px.len > (0xff & (v2.val.px.len >> 8))))) | |
84 | return 0; | |
85 | return 1; | |
86 | } | |
87 | return CMP_ERROR; | |
88 | } | |
89 | ||
7db7b7db PM |
90 | int |
91 | val_in_range(struct f_val v1, struct f_val v2) | |
92 | { | |
6dc7a0cb PM |
93 | int res; |
94 | ||
95 | res = val_simple_in_range(v1, v2); | |
96 | ||
97 | if (res != CMP_ERROR) | |
98 | return res; | |
99 | ||
2f702671 | 100 | if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) { |
6dc7a0cb PM |
101 | struct f_tree *n; |
102 | n = find_tree(v2.val.t, v1); | |
103 | if (!n) | |
104 | return 0; | |
105 | return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */ | |
106 | } | |
7db7b7db PM |
107 | return CMP_ERROR; |
108 | } | |
109 | ||
38506f71 PM |
110 | static void |
111 | tree_print(struct f_tree *t) | |
112 | { | |
113 | if (!t) { | |
114 | printf( "() " ); | |
115 | return; | |
116 | } | |
117 | printf( "[ " ); | |
118 | tree_print( t->left ); | |
119 | printf( ", " ); val_print( t->from ); printf( ".." ); val_print( t->to ); printf( ", " ); | |
120 | tree_print( t->right ); | |
121 | printf( "] " ); | |
122 | } | |
123 | ||
124 | void | |
125 | val_print(struct f_val v) | |
126 | { | |
127 | char buf[2048]; | |
128 | #define PRINTF(a...) bsnprintf( buf, 2040, a ) | |
129 | buf[0] = 0; | |
130 | switch (v.type) { | |
131 | case T_VOID: PRINTF( "(void)" ); break; | |
132 | case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break; | |
133 | case T_INT: PRINTF( "%d ", v.val.i ); break; | |
134 | case T_STRING: PRINTF( "%s", v.val.s ); break; | |
6dc7a0cb | 135 | case T_IP: PRINTF( "%I", v.val.px.ip ); break; |
720d911d PM |
136 | case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break; |
137 | case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break; | |
38506f71 | 138 | case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break; |
346a12c2 | 139 | case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break; |
38506f71 PM |
140 | default: PRINTF( "[unknown type %x]", v.type ); |
141 | } | |
142 | printf( buf ); | |
143 | } | |
144 | ||
48f9e019 | 145 | static struct rte **f_rte, *f_rte_old; |
f31156ca | 146 | static struct linpool *f_pool; |
31e79264 | 147 | static struct ea_list **f_tmp_attrs; |
36bbfc70 | 148 | |
9a4037d4 PM |
149 | #define runtime(x) do { \ |
150 | log( L_ERR x ); \ | |
151 | res.type = T_RETURN; \ | |
152 | res.val.i = F_ERROR; \ | |
153 | return res; \ | |
154 | } while(0) | |
155 | ||
156 | #define ARG(x,y) \ | |
157 | x = interpret(what->y); \ | |
2d496d20 | 158 | if (x.type & T_RETURN) \ |
9a4037d4 PM |
159 | return x; |
160 | ||
161 | #define ONEARG ARG(v1, a1.p) | |
162 | #define TWOARGS ARG(v1, a1.p) \ | |
163 | ARG(v2, a2.p) | |
164 | #define TWOARGS_C TWOARGS \ | |
165 | if (v1.type != v2.type) \ | |
166 | runtime( "Can not operate with values of incompatible types" ); | |
7db7b7db | 167 | |
23b1539b PM |
168 | static struct f_val |
169 | interpret(struct f_inst *what) | |
170 | { | |
171 | struct symbol *sym; | |
172 | struct f_val v1, v2, res; | |
38506f71 | 173 | int i,j,k; |
23b1539b PM |
174 | |
175 | res.type = T_VOID; | |
176 | if (!what) | |
177 | return res; | |
178 | ||
179 | switch(what->code) { | |
180 | case ',': | |
181 | TWOARGS; | |
182 | break; | |
183 | ||
184 | /* Binary operators */ | |
185 | case '+': | |
186 | TWOARGS_C; | |
187 | switch (res.type = v1.type) { | |
188 | case T_VOID: runtime( "Can not operate with values of type void" ); | |
189 | case T_INT: res.val.i = v1.val.i + v2.val.i; break; | |
190 | default: runtime( "Usage of unknown type" ); | |
191 | } | |
192 | break; | |
193 | case '/': | |
194 | TWOARGS_C; | |
195 | switch (res.type = v1.type) { | |
196 | case T_VOID: runtime( "Can not operate with values of type void" ); | |
197 | case T_INT: res.val.i = v1.val.i / v2.val.i; break; | |
198 | case T_IP: if (v2.type != T_INT) | |
199 | runtime( "Operator / is <ip>/<int>" ); | |
200 | break; | |
201 | default: runtime( "Usage of unknown type" ); | |
202 | } | |
203 | break; | |
204 | ||
205 | /* Relational operators */ | |
38506f71 PM |
206 | |
207 | #define COMPARE(x) \ | |
208 | TWOARGS_C; \ | |
209 | res.type = T_BOOL; \ | |
210 | i = val_compare(v1, v2); \ | |
211 | if (i==CMP_ERROR) \ | |
212 | runtime( "Error in comparation" ); \ | |
213 | res.val.i = (x); \ | |
23b1539b | 214 | break; |
38506f71 | 215 | |
2d496d20 PM |
216 | case P('!','='): COMPARE(i!=0); |
217 | case P('=','='): COMPARE(i==0); | |
38506f71 | 218 | case '<': COMPARE(i==-1); |
2d496d20 | 219 | case P('<','='): COMPARE(i!=1); |
38506f71 | 220 | |
995e5894 PM |
221 | case '!': |
222 | ONEARG; | |
223 | if (v1.type != T_BOOL) | |
224 | runtime( "not applied to non-boolean" ); | |
225 | res = v1; | |
226 | res.val.i = !res.val.i; | |
227 | break; | |
228 | ||
38506f71 PM |
229 | case '~': |
230 | TWOARGS; | |
23b1539b | 231 | res.type = T_BOOL; |
7db7b7db PM |
232 | res.val.i = val_in_range(v1, v2); |
233 | if (res.val.i == CMP_ERROR) | |
234 | runtime( "~ applied on unknown type pair" ); | |
23b1539b | 235 | break; |
2d496d20 | 236 | case P('d','e'): |
f4536657 PM |
237 | ONEARG; |
238 | res.type = T_BOOL; | |
239 | res.val.i = (v1.type != T_VOID); | |
240 | break; | |
23b1539b | 241 | |
d3dd620b | 242 | /* Set to indirect value, a1 = variable, a2 = value */ |
23b1539b | 243 | case 's': |
2db3b288 PM |
244 | ARG(v2, a2.p); |
245 | sym = what->a1.p; | |
23b1539b PM |
246 | switch (res.type = v2.type) { |
247 | case T_VOID: runtime( "Can not assign void values" ); | |
f4536657 | 248 | case T_ENUM: |
23b1539b | 249 | case T_INT: |
d3dd620b PM |
250 | case T_IP: |
251 | case T_PREFIX: | |
252 | case T_PAIR: | |
253 | if (sym->class != (SYM_VARIABLE | v2.type)) | |
23b1539b | 254 | runtime( "Variable of bad type" ); |
d3dd620b | 255 | * (struct f_val *) sym->aux2 = v2; |
23b1539b | 256 | break; |
d3dd620b PM |
257 | default: |
258 | bug( "Set to invalid type\n" ); | |
23b1539b PM |
259 | } |
260 | break; | |
261 | ||
d3dd620b | 262 | case 'c': /* integer (or simple type) constant */ |
c7b43f33 | 263 | res.type = what->aux; |
d3dd620b | 264 | res.val.i = what->a2.i; |
23b1539b | 265 | break; |
38506f71 PM |
266 | case 'C': |
267 | res = * ((struct f_val *) what->a1.p); | |
268 | break; | |
23b1539b PM |
269 | case 'p': |
270 | ONEARG; | |
38506f71 | 271 | val_print(v1); |
23b1539b PM |
272 | break; |
273 | case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ | |
274 | ONEARG; | |
275 | if (v1.type != T_BOOL) | |
276 | runtime( "If requires bool expression" ); | |
277 | if (v1.val.i) { | |
2db3b288 | 278 | ARG(res,a2.p); |
23b1539b PM |
279 | res.val.i = 0; |
280 | } else res.val.i = 1; | |
281 | res.type = T_BOOL; | |
282 | break; | |
283 | case '0': | |
284 | printf( "No operation\n" ); | |
285 | break; | |
2d496d20 | 286 | case P('p',','): |
23b1539b | 287 | ONEARG; |
d3dd620b PM |
288 | if (what->a2.i != F_NONL) |
289 | printf( "\n" ); | |
23b1539b | 290 | |
2db3b288 | 291 | switch (what->a2.i) { |
23b1539b PM |
292 | case F_QUITBIRD: |
293 | die( "Filter asked me to die" ); | |
294 | case F_ACCEPT: | |
295 | /* Should take care about turning ACCEPT into MODIFY */ | |
296 | case F_ERROR: | |
2ad6dcdb | 297 | case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */ |
23b1539b | 298 | res.type = T_RETURN; |
2ad6dcdb | 299 | res.val.i = what->a2.i; |
7e1f9971 | 300 | return res; /* We have to return now, no more processing. */ |
d3dd620b | 301 | case F_NONL: |
23b1539b PM |
302 | case F_NOP: |
303 | break; | |
304 | default: | |
305 | bug( "unknown return type: can not happen"); | |
306 | } | |
307 | break; | |
36bbfc70 PM |
308 | case 'a': /* rta access */ |
309 | { | |
310 | struct rta *rta = (*f_rte)->attrs; | |
c7b43f33 | 311 | res.type = what->aux; |
36bbfc70 PM |
312 | switch(res.type) { |
313 | case T_IP: | |
6dc7a0cb | 314 | res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i); |
36bbfc70 | 315 | break; |
c7b43f33 PM |
316 | case T_ENUM: |
317 | res.val.i = * ((char *) rta + what->a2.i); | |
318 | break; | |
36bbfc70 PM |
319 | case T_PREFIX: /* Warning: this works only for prefix of network */ |
320 | { | |
321 | res.val.px.ip = (*f_rte)->net->n.prefix; | |
322 | res.val.px.len = (*f_rte)->net->n.pxlen; | |
323 | break; | |
324 | } | |
325 | default: | |
4aa885a5 | 326 | bug( "Invalid type for rta access (%x)\n" ); |
36bbfc70 PM |
327 | } |
328 | } | |
329 | break; | |
2d496d20 | 330 | case P('e','a'): /* Access to extended attributes */ |
91447965 PM |
331 | { |
332 | eattr *e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); | |
31e79264 PM |
333 | if (!e) |
334 | e = ea_find( (*f_tmp_attrs), what->a2.i ); | |
91447965 PM |
335 | if (!e) { |
336 | res.type = T_VOID; | |
337 | break; | |
338 | } | |
c7b43f33 | 339 | res.type = what->aux; |
91447965 PM |
340 | switch (what->a1.i) { |
341 | case T_INT: | |
342 | res.val.i = e->u.data; | |
343 | break; | |
344 | } | |
345 | } | |
6dc7a0cb | 346 | break; |
2d496d20 | 347 | case P('e','S'): |
f31156ca PM |
348 | ONEARG; |
349 | if (v1.type != what->aux) | |
350 | runtime("Wrong type when setting dynamic attribute\n"); | |
351 | ||
f31156ca PM |
352 | { |
353 | struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); | |
354 | ||
355 | l->next = NULL; | |
356 | l->flags = EALF_SORTED; | |
357 | l->count = 1; | |
358 | l->attrs[0].id = what->a2.i; | |
359 | l->attrs[0].flags = 0; | |
31e79264 PM |
360 | l->attrs[0].type = what->aux; |
361 | switch (what->aux & EAF_TYPE_MASK) { | |
362 | case EAF_TYPE_INT: | |
363 | if (v1.type != T_INT) | |
364 | runtime( "Setting int attribute to non-int value" ); | |
f31156ca PM |
365 | l->attrs[0].u.data = v1.val.i; |
366 | break; | |
31e79264 PM |
367 | case EAF_TYPE_UNDEF: |
368 | if (v1.type != T_VOID) | |
369 | runtime( "Setting void attribute to non-void value" ); | |
48f9e019 PM |
370 | l->attrs[0].u.data = 0; |
371 | break; | |
f31156ca | 372 | } |
31e79264 | 373 | |
9f4929e7 | 374 | if (!(what->aux & EAF_TEMP)) { |
31e79264 PM |
375 | *f_rte = rte_do_cow(*f_rte); |
376 | l->next = (*f_rte)->attrs->eattrs; | |
377 | (*f_rte)->attrs->eattrs = l; | |
378 | } else { | |
379 | l->next = (*f_tmp_attrs); | |
380 | (*f_tmp_attrs) = l; | |
381 | } | |
f31156ca | 382 | } |
f31156ca | 383 | break; |
48f9e019 | 384 | |
2d496d20 | 385 | case P('c','p'): /* Convert prefix to ... */ |
36bbfc70 PM |
386 | ONEARG; |
387 | if (v1.type != T_PREFIX) | |
388 | runtime( "Can not convert non-prefix this way" ); | |
c7b43f33 | 389 | res.type = what->aux; |
36bbfc70 PM |
390 | switch(res.type) { |
391 | case T_INT: res.val.i = v1.val.px.len; break; | |
6dc7a0cb | 392 | case T_IP: res.val.px.ip = v1.val.px.ip; break; |
36bbfc70 PM |
393 | default: bug( "Unknown prefix to conversion\n" ); |
394 | } | |
395 | break; | |
2d496d20 PM |
396 | case 'r': |
397 | ONEARG; | |
398 | res = v1; | |
399 | res.type |= T_RETURN; | |
400 | break; | |
401 | case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */ | |
6542ece9 PM |
402 | ONEARG; |
403 | res = interpret(what->a2.p); | |
2d496d20 PM |
404 | if (res.type == T_RETURN) |
405 | return res; | |
406 | res.type &= ~T_RETURN; | |
6542ece9 | 407 | break; |
2d496d20 | 408 | case P('S','W'): |
7db7b7db | 409 | ONEARG; |
41be4444 PM |
410 | { |
411 | struct f_tree *t = find_tree(what->a2.p, v1); | |
412 | if (!t) { | |
413 | v1.type = T_VOID; | |
414 | t = find_tree(what->a2.p, v1); | |
415 | if (!t) { | |
416 | printf( "No else statement?\n "); | |
417 | break; | |
418 | } | |
419 | } | |
420 | if (!t->data) | |
421 | die( "Impossible: no code associated!\n" ); | |
422 | return interpret(t->data); | |
423 | } | |
7db7b7db | 424 | break; |
2d496d20 | 425 | case P('i','M'): /* IP.MASK(val) */ |
f4536657 PM |
426 | TWOARGS; |
427 | if (v2.type != T_INT) | |
428 | runtime( "Can not use this type for mask."); | |
429 | if (v1.type != T_IP) | |
430 | runtime( "You can mask only IP addresses." ); | |
431 | { | |
432 | ip_addr mask = ipa_mkmask(v2.val.i); | |
433 | res.type = T_IP; | |
434 | res.val.px.ip = ipa_and(mask, v1.val.px.ip); | |
435 | } | |
d3dd620b | 436 | break; |
23b1539b PM |
437 | default: |
438 | bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); | |
439 | } | |
440 | if (what->next) | |
441 | return interpret(what->next); | |
442 | return res; | |
443 | } | |
444 | ||
2d496d20 | 445 | #undef ARG |
9a4037d4 PM |
446 | #define ARG(x,y) \ |
447 | if (!i_same(f1->y, f2->y)) \ | |
448 | return 0; | |
449 | ||
450 | #define ONEARG ARG(v1, a1.p) | |
451 | #define TWOARGS ARG(v1, a1.p) \ | |
452 | ARG(v2, a2.p) | |
453 | ||
454 | #define A2_SAME if (f1->a2.i != f2->a2.i) return 0; | |
455 | ||
456 | int | |
457 | i_same(struct f_inst *f1, struct f_inst *f2) | |
458 | { | |
9a4037d4 PM |
459 | if ((!!f1) != (!!f2)) |
460 | return 0; | |
d4d75628 PM |
461 | if (!f1) |
462 | return 1; | |
9a4037d4 PM |
463 | if (f1->aux != f2->aux) |
464 | return 0; | |
465 | if (f1->code != f2->code) | |
466 | return 0; | |
d4d75628 PM |
467 | if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ |
468 | return 1; | |
9a4037d4 PM |
469 | |
470 | switch(f1->code) { | |
471 | case ',': /* fall through */ | |
472 | case '+': | |
473 | case '/': | |
2d496d20 PM |
474 | case P('!','='): |
475 | case P('=','='): | |
9a4037d4 | 476 | case '<': |
2d496d20 | 477 | case P('<','='): TWOARGS; break; |
9a4037d4 | 478 | |
995e5894 | 479 | case '!': ONEARG; break; |
9a4037d4 | 480 | case '~': TWOARGS; break; |
2d496d20 | 481 | case P('d','e'): ONEARG; break; |
9a4037d4 PM |
482 | |
483 | case 's': | |
484 | ARG(v2, a2.p); | |
485 | { | |
486 | struct symbol *s1, *s2; | |
487 | s1 = f1->a1.p; | |
488 | s2 = f2->a1.p; | |
489 | if (strcmp(s1->name, s2->name)) | |
490 | return 0; | |
491 | if (s1->class != s2->class) | |
492 | return 0; | |
493 | } | |
494 | break; | |
495 | ||
496 | case 'c': A2_SAME; break; | |
497 | case 'C': | |
498 | if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a2.p)) | |
499 | return 0; | |
500 | break; | |
501 | case 'p': ONEARG; break; | |
502 | case '?': TWOARGS; break; | |
503 | case '0': break; | |
2d496d20 | 504 | case P('p',','): ONEARG; A2_SAME; break; |
9a4037d4 | 505 | case 'a': A2_SAME; break; |
2d496d20 PM |
506 | case P('e','a'): A2_SAME; break; |
507 | case P('e','S'): ONEARG; A2_SAME; break; | |
9a4037d4 | 508 | |
2d496d20 PM |
509 | case 'r': ONEARG; break; |
510 | case P('c','p'): ONEARG; break; | |
d4d75628 PM |
511 | case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ |
512 | ONEARG; | |
513 | if (!i_same(f1->a2.p, f2->a2.p)) | |
514 | return 0; | |
515 | f2->a2.p = f1->a2.p; | |
516 | break; | |
2d496d20 PM |
517 | case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; |
518 | case P('i','M'): TWOARGS; break; | |
9a4037d4 PM |
519 | default: |
520 | bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); | |
521 | } | |
522 | return i_same(f1->next, f2->next); | |
523 | } | |
524 | ||
23b1539b PM |
525 | int |
526 | f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool) | |
527 | { | |
528 | struct f_inst *inst; | |
529 | struct f_val res; | |
6b9fa320 | 530 | DBG( "Running filter `%s'...", filter->name ); |
23b1539b | 531 | |
31e79264 | 532 | f_tmp_attrs = tmp_attrs; |
36bbfc70 | 533 | f_rte = rte; |
48f9e019 | 534 | f_rte_old = *rte; |
f31156ca | 535 | f_pool = tmp_pool; |
23b1539b PM |
536 | inst = filter->root; |
537 | res = interpret(inst); | |
538 | if (res.type != T_RETURN) | |
539 | return F_ERROR; | |
6b9fa320 | 540 | DBG( "done (%d)\n", res.val.i ); |
23b1539b PM |
541 | return res.val.i; |
542 | } | |
543 | ||
23b1539b PM |
544 | void |
545 | filters_postconfig(void) | |
546 | { | |
547 | struct f_val res; | |
8ba2cc06 PM |
548 | if (startup_func) { |
549 | printf( "Launching startup function...\n" ); | |
23b1539b | 550 | res = interpret(startup_func); |
bad631e0 | 551 | if (res.type == F_ERROR) |
8ba2cc06 PM |
552 | die( "Startup function resulted in error." ); |
553 | printf( "done\n" ); | |
554 | } | |
23b1539b | 555 | } |
30a6108c MM |
556 | |
557 | int | |
558 | filter_same(struct filter *new, struct filter *old) | |
559 | { | |
9a4037d4 | 560 | return i_same(new->root, old->root); |
30a6108c | 561 | } |