]>
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 | ||
78c6217c | 12 | #define LOCAL_DEBUG |
6b9fa320 | 13 | |
23b1539b PM |
14 | #include "nest/bird.h" |
15 | #include "lib/lists.h" | |
16 | #include "lib/resource.h" | |
17 | #include "lib/socket.h" | |
38506f71 | 18 | #include "lib/string.h" |
7f77e250 | 19 | #include "lib/unaligned.h" |
23b1539b PM |
20 | #include "nest/route.h" |
21 | #include "nest/protocol.h" | |
22 | #include "nest/iface.h" | |
159fa4ce | 23 | #include "nest/attrs.h" |
23b1539b PM |
24 | #include "conf/conf.h" |
25 | #include "filter/filter.h" | |
26 | ||
2d496d20 PM |
27 | #define P(a,b) ((a<<8) | b) |
28 | ||
23b1539b PM |
29 | struct f_inst *startup_func = NULL; |
30 | ||
38506f71 PM |
31 | #define CMP_ERROR 999 |
32 | ||
33 | /* Compare two values, returns -1, 0, 1 compared, ERROR 999 */ | |
34 | int | |
35 | val_compare(struct f_val v1, struct f_val v2) | |
36 | { | |
41be4444 PM |
37 | if ((v1.type == T_VOID) && (v2.type == T_VOID)) |
38 | return 0; | |
39 | if (v1.type == T_VOID) /* Hack for else */ | |
40 | return -1; | |
41 | if (v2.type == T_VOID) | |
42 | return 1; | |
43 | ||
7db7b7db PM |
44 | if (v1.type != v2.type) |
45 | return CMP_ERROR; | |
38506f71 | 46 | switch (v1.type) { |
f4536657 | 47 | case T_ENUM: |
38506f71 | 48 | case T_INT: |
d3dd620b | 49 | case T_PAIR: |
38506f71 PM |
50 | if (v1.val.i == v2.val.i) return 0; |
51 | if (v1.val.i < v2.val.i) return -1; | |
52 | return 1; | |
43fc099b | 53 | case T_IP: |
6dc7a0cb PM |
54 | case T_PREFIX: |
55 | return ipa_compare(v1.val.px.ip, v2.val.px.ip); | |
3076b5ae MM |
56 | default: |
57 | return CMP_ERROR; | |
38506f71 PM |
58 | } |
59 | } | |
60 | ||
6dc7a0cb PM |
61 | int |
62 | val_simple_in_range(struct f_val v1, struct f_val v2) | |
63 | { | |
10a53608 | 64 | if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) |
2a40efa5 | 65 | return as_path_match(v1.val.ad, v2.val.path_mask); |
10a53608 | 66 | |
6dc7a0cb PM |
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) { | |
3cf4a2e2 | 114 | debug( "() " ); |
38506f71 PM |
115 | return; |
116 | } | |
3cf4a2e2 | 117 | debug( "[ " ); |
38506f71 | 118 | tree_print( t->left ); |
3cf4a2e2 | 119 | debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " ); |
38506f71 | 120 | tree_print( t->right ); |
3cf4a2e2 | 121 | debug( "] " ); |
38506f71 PM |
122 | } |
123 | ||
124 | void | |
125 | val_print(struct f_val v) | |
126 | { | |
127 | char buf[2048]; | |
ecd25633 | 128 | char buf2[1024]; |
38506f71 PM |
129 | #define PRINTF(a...) bsnprintf( buf, 2040, a ) |
130 | buf[0] = 0; | |
131 | switch (v.type) { | |
132 | case T_VOID: PRINTF( "(void)" ); break; | |
133 | case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break; | |
134 | case T_INT: PRINTF( "%d ", v.val.i ); break; | |
135 | case T_STRING: PRINTF( "%s", v.val.s ); break; | |
6dc7a0cb | 136 | case T_IP: PRINTF( "%I", v.val.px.ip ); break; |
720d911d PM |
137 | case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break; |
138 | case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break; | |
38506f71 | 139 | case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break; |
346a12c2 | 140 | case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break; |
ecd25633 | 141 | case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break; |
159fa4ce | 142 | case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break; |
ecd25633 | 143 | case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.s; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break; |
38506f71 | 144 | default: PRINTF( "[unknown type %x]", v.type ); |
7f77e250 | 145 | #undef PRINTF |
38506f71 | 146 | } |
3cf4a2e2 | 147 | debug( buf ); |
38506f71 PM |
148 | } |
149 | ||
48f9e019 | 150 | static struct rte **f_rte, *f_rte_old; |
f31156ca | 151 | static struct linpool *f_pool; |
31e79264 | 152 | static struct ea_list **f_tmp_attrs; |
0a06a9b8 | 153 | static int f_flags; |
36bbfc70 | 154 | |
9a4037d4 PM |
155 | #define runtime(x) do { \ |
156 | log( L_ERR x ); \ | |
157 | res.type = T_RETURN; \ | |
158 | res.val.i = F_ERROR; \ | |
159 | return res; \ | |
160 | } while(0) | |
161 | ||
162 | #define ARG(x,y) \ | |
163 | x = interpret(what->y); \ | |
2d496d20 | 164 | if (x.type & T_RETURN) \ |
9a4037d4 PM |
165 | return x; |
166 | ||
167 | #define ONEARG ARG(v1, a1.p) | |
168 | #define TWOARGS ARG(v1, a1.p) \ | |
169 | ARG(v2, a2.p) | |
170 | #define TWOARGS_C TWOARGS \ | |
171 | if (v1.type != v2.type) \ | |
172 | runtime( "Can not operate with values of incompatible types" ); | |
7db7b7db | 173 | |
23b1539b PM |
174 | static struct f_val |
175 | interpret(struct f_inst *what) | |
176 | { | |
177 | struct symbol *sym; | |
178 | struct f_val v1, v2, res; | |
38506f71 | 179 | int i,j,k; |
23b1539b PM |
180 | |
181 | res.type = T_VOID; | |
182 | if (!what) | |
183 | return res; | |
184 | ||
185 | switch(what->code) { | |
186 | case ',': | |
187 | TWOARGS; | |
188 | break; | |
189 | ||
190 | /* Binary operators */ | |
191 | case '+': | |
192 | TWOARGS_C; | |
193 | switch (res.type = v1.type) { | |
194 | case T_VOID: runtime( "Can not operate with values of type void" ); | |
195 | case T_INT: res.val.i = v1.val.i + v2.val.i; break; | |
196 | default: runtime( "Usage of unknown type" ); | |
197 | } | |
198 | break; | |
199 | case '/': | |
200 | TWOARGS_C; | |
201 | switch (res.type = v1.type) { | |
202 | case T_VOID: runtime( "Can not operate with values of type void" ); | |
203 | case T_INT: res.val.i = v1.val.i / v2.val.i; break; | |
204 | case T_IP: if (v2.type != T_INT) | |
205 | runtime( "Operator / is <ip>/<int>" ); | |
206 | break; | |
207 | default: runtime( "Usage of unknown type" ); | |
208 | } | |
209 | break; | |
210 | ||
211 | /* Relational operators */ | |
38506f71 PM |
212 | |
213 | #define COMPARE(x) \ | |
214 | TWOARGS_C; \ | |
215 | res.type = T_BOOL; \ | |
216 | i = val_compare(v1, v2); \ | |
217 | if (i==CMP_ERROR) \ | |
218 | runtime( "Error in comparation" ); \ | |
219 | res.val.i = (x); \ | |
23b1539b | 220 | break; |
38506f71 | 221 | |
2d496d20 PM |
222 | case P('!','='): COMPARE(i!=0); |
223 | case P('=','='): COMPARE(i==0); | |
38506f71 | 224 | case '<': COMPARE(i==-1); |
2d496d20 | 225 | case P('<','='): COMPARE(i!=1); |
38506f71 | 226 | |
995e5894 PM |
227 | case '!': |
228 | ONEARG; | |
229 | if (v1.type != T_BOOL) | |
230 | runtime( "not applied to non-boolean" ); | |
231 | res = v1; | |
232 | res.val.i = !res.val.i; | |
233 | break; | |
234 | ||
38506f71 PM |
235 | case '~': |
236 | TWOARGS; | |
23b1539b | 237 | res.type = T_BOOL; |
7db7b7db PM |
238 | res.val.i = val_in_range(v1, v2); |
239 | if (res.val.i == CMP_ERROR) | |
240 | runtime( "~ applied on unknown type pair" ); | |
23b1539b | 241 | break; |
2d496d20 | 242 | case P('d','e'): |
f4536657 PM |
243 | ONEARG; |
244 | res.type = T_BOOL; | |
245 | res.val.i = (v1.type != T_VOID); | |
246 | break; | |
23b1539b | 247 | |
d3dd620b | 248 | /* Set to indirect value, a1 = variable, a2 = value */ |
23b1539b | 249 | case 's': |
2db3b288 PM |
250 | ARG(v2, a2.p); |
251 | sym = what->a1.p; | |
23b1539b PM |
252 | switch (res.type = v2.type) { |
253 | case T_VOID: runtime( "Can not assign void values" ); | |
f4536657 | 254 | case T_ENUM: |
23b1539b | 255 | case T_INT: |
d3dd620b PM |
256 | case T_IP: |
257 | case T_PREFIX: | |
258 | case T_PAIR: | |
e399b6f6 PM |
259 | case T_PATH: |
260 | case T_CLIST: | |
dcab7890 | 261 | case T_PATH_MASK: |
d3dd620b | 262 | if (sym->class != (SYM_VARIABLE | v2.type)) |
23b1539b | 263 | runtime( "Variable of bad type" ); |
d3dd620b | 264 | * (struct f_val *) sym->aux2 = v2; |
23b1539b | 265 | break; |
d3dd620b | 266 | default: |
3076b5ae | 267 | bug( "Set to invalid type" ); |
23b1539b PM |
268 | } |
269 | break; | |
270 | ||
d3dd620b | 271 | case 'c': /* integer (or simple type) constant */ |
c7b43f33 | 272 | res.type = what->aux; |
d3dd620b | 273 | res.val.i = what->a2.i; |
23b1539b | 274 | break; |
38506f71 PM |
275 | case 'C': |
276 | res = * ((struct f_val *) what->a1.p); | |
277 | break; | |
23b1539b PM |
278 | case 'p': |
279 | ONEARG; | |
38506f71 | 280 | val_print(v1); |
23b1539b PM |
281 | break; |
282 | case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ | |
283 | ONEARG; | |
284 | if (v1.type != T_BOOL) | |
285 | runtime( "If requires bool expression" ); | |
286 | if (v1.val.i) { | |
2db3b288 | 287 | ARG(res,a2.p); |
23b1539b PM |
288 | res.val.i = 0; |
289 | } else res.val.i = 1; | |
290 | res.type = T_BOOL; | |
291 | break; | |
292 | case '0': | |
3cf4a2e2 | 293 | debug( "No operation\n" ); |
23b1539b | 294 | break; |
2d496d20 | 295 | case P('p',','): |
23b1539b | 296 | ONEARG; |
798df5b1 | 297 | if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) |
3cf4a2e2 | 298 | debug( "\n" ); |
23b1539b | 299 | |
2db3b288 | 300 | switch (what->a2.i) { |
23b1539b PM |
301 | case F_QUITBIRD: |
302 | die( "Filter asked me to die" ); | |
303 | case F_ACCEPT: | |
304 | /* Should take care about turning ACCEPT into MODIFY */ | |
305 | case F_ERROR: | |
2ad6dcdb | 306 | case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */ |
23b1539b | 307 | res.type = T_RETURN; |
2ad6dcdb | 308 | res.val.i = what->a2.i; |
7e1f9971 | 309 | return res; /* We have to return now, no more processing. */ |
d3dd620b | 310 | case F_NONL: |
23b1539b PM |
311 | case F_NOP: |
312 | break; | |
313 | default: | |
314 | bug( "unknown return type: can not happen"); | |
315 | } | |
316 | break; | |
36bbfc70 PM |
317 | case 'a': /* rta access */ |
318 | { | |
319 | struct rta *rta = (*f_rte)->attrs; | |
c7b43f33 | 320 | res.type = what->aux; |
36bbfc70 PM |
321 | switch(res.type) { |
322 | case T_IP: | |
6dc7a0cb | 323 | res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i); |
36bbfc70 | 324 | break; |
c7b43f33 PM |
325 | case T_ENUM: |
326 | res.val.i = * ((char *) rta + what->a2.i); | |
327 | break; | |
36bbfc70 PM |
328 | case T_PREFIX: /* Warning: this works only for prefix of network */ |
329 | { | |
330 | res.val.px.ip = (*f_rte)->net->n.prefix; | |
331 | res.val.px.len = (*f_rte)->net->n.pxlen; | |
332 | break; | |
333 | } | |
334 | default: | |
3076b5ae | 335 | bug( "Invalid type for rta access (%x)", res.type ); |
36bbfc70 PM |
336 | } |
337 | } | |
338 | break; | |
2d496d20 | 339 | case P('e','a'): /* Access to extended attributes */ |
91447965 | 340 | { |
0a06a9b8 | 341 | eattr *e = NULL; |
3076b5ae | 342 | if (!(f_flags & FF_FORCE_TMPATTR)) |
0a06a9b8 | 343 | e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); |
31e79264 PM |
344 | if (!e) |
345 | e = ea_find( (*f_tmp_attrs), what->a2.i ); | |
3076b5ae | 346 | if ((!e) && (f_flags & FF_FORCE_TMPATTR)) |
0a06a9b8 PM |
347 | e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); |
348 | ||
91447965 PM |
349 | if (!e) { |
350 | res.type = T_VOID; | |
351 | break; | |
352 | } | |
10a53608 | 353 | res.type = what->aux; /* FIXME: should check type? */ |
2803c9dd | 354 | switch (what->aux) { |
91447965 PM |
355 | case T_INT: |
356 | res.val.i = e->u.data; | |
357 | break; | |
10a53608 PM |
358 | case T_PATH: |
359 | res.val.ad = e->u.ptr; | |
360 | break; | |
2803c9dd MM |
361 | default: |
362 | bug("Unknown type in e,a\n"); | |
91447965 PM |
363 | } |
364 | } | |
6dc7a0cb | 365 | break; |
2d496d20 | 366 | case P('e','S'): |
f31156ca PM |
367 | ONEARG; |
368 | if (v1.type != what->aux) | |
3076b5ae | 369 | runtime("Wrong type when setting dynamic attribute"); |
f31156ca | 370 | |
f31156ca PM |
371 | { |
372 | struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); | |
373 | ||
374 | l->next = NULL; | |
375 | l->flags = EALF_SORTED; | |
376 | l->count = 1; | |
377 | l->attrs[0].id = what->a2.i; | |
991c36b5 | 378 | l->attrs[0].flags = EAF_ORIGINATED; |
31e79264 PM |
379 | l->attrs[0].type = what->aux; |
380 | switch (what->aux & EAF_TYPE_MASK) { | |
381 | case EAF_TYPE_INT: | |
382 | if (v1.type != T_INT) | |
383 | runtime( "Setting int attribute to non-int value" ); | |
f31156ca PM |
384 | l->attrs[0].u.data = v1.val.i; |
385 | break; | |
10a53608 PM |
386 | case EAF_TYPE_AS_PATH: |
387 | if (v1.type != T_PATH) | |
388 | runtime( "Setting path attribute to non-path value" ); | |
389 | l->attrs[0].u.ptr = v1.val.ad; | |
390 | break; | |
31e79264 PM |
391 | case EAF_TYPE_UNDEF: |
392 | if (v1.type != T_VOID) | |
393 | runtime( "Setting void attribute to non-void value" ); | |
48f9e019 PM |
394 | l->attrs[0].u.data = 0; |
395 | break; | |
f31156ca | 396 | } |
31e79264 | 397 | |
3076b5ae MM |
398 | if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) { |
399 | *f_rte = rte_cow(*f_rte); | |
31e79264 PM |
400 | l->next = (*f_rte)->attrs->eattrs; |
401 | (*f_rte)->attrs->eattrs = l; | |
402 | } else { | |
403 | l->next = (*f_tmp_attrs); | |
404 | (*f_tmp_attrs) = l; | |
405 | } | |
f31156ca | 406 | } |
f31156ca | 407 | break; |
48f9e019 | 408 | |
684c6f5a PM |
409 | case 'L': /* Get length of */ |
410 | ONEARG; | |
411 | res.type = T_INT; | |
412 | switch(v1.type) { | |
413 | case T_PREFIX: res.val.i = v1.val.px.len; break; | |
414 | case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; | |
415 | default: bug( "Length of what?" ); | |
416 | } | |
417 | break; | |
2d496d20 | 418 | case P('c','p'): /* Convert prefix to ... */ |
36bbfc70 PM |
419 | ONEARG; |
420 | if (v1.type != T_PREFIX) | |
421 | runtime( "Can not convert non-prefix this way" ); | |
c7b43f33 | 422 | res.type = what->aux; |
36bbfc70 | 423 | switch(res.type) { |
684c6f5a | 424 | /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */ |
6dc7a0cb | 425 | case T_IP: res.val.px.ip = v1.val.px.ip; break; |
3076b5ae | 426 | default: bug( "Unknown prefix to conversion" ); |
36bbfc70 PM |
427 | } |
428 | break; | |
2d496d20 PM |
429 | case 'r': |
430 | ONEARG; | |
431 | res = v1; | |
432 | res.type |= T_RETURN; | |
433 | break; | |
434 | case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */ | |
6542ece9 PM |
435 | ONEARG; |
436 | res = interpret(what->a2.p); | |
2d496d20 PM |
437 | if (res.type == T_RETURN) |
438 | return res; | |
439 | res.type &= ~T_RETURN; | |
6542ece9 | 440 | break; |
2d496d20 | 441 | case P('S','W'): |
7db7b7db | 442 | ONEARG; |
41be4444 PM |
443 | { |
444 | struct f_tree *t = find_tree(what->a2.p, v1); | |
445 | if (!t) { | |
446 | v1.type = T_VOID; | |
447 | t = find_tree(what->a2.p, v1); | |
448 | if (!t) { | |
3cf4a2e2 | 449 | debug( "No else statement?\n "); |
41be4444 PM |
450 | break; |
451 | } | |
452 | } | |
453 | if (!t->data) | |
3076b5ae | 454 | bug( "Impossible: no code associated!" ); |
41be4444 PM |
455 | return interpret(t->data); |
456 | } | |
7db7b7db | 457 | break; |
2d496d20 | 458 | case P('i','M'): /* IP.MASK(val) */ |
f4536657 PM |
459 | TWOARGS; |
460 | if (v2.type != T_INT) | |
461 | runtime( "Can not use this type for mask."); | |
462 | if (v1.type != T_IP) | |
463 | runtime( "You can mask only IP addresses." ); | |
464 | { | |
465 | ip_addr mask = ipa_mkmask(v2.val.i); | |
466 | res.type = T_IP; | |
467 | res.val.px.ip = ipa_and(mask, v1.val.px.ip); | |
468 | } | |
d3dd620b | 469 | break; |
afc54517 PM |
470 | |
471 | case 'E': /* Create empty attribute */ | |
472 | res.type = what->aux; | |
473 | res.val.ad = adata_empty(f_pool); | |
474 | break; | |
475 | case P('A','p'): /* Path prepend */ | |
476 | TWOARGS; | |
477 | if (v1.type != T_PATH) | |
478 | runtime("Can't prepend to non-path"); | |
479 | if (v2.type != T_INT) | |
480 | runtime("Can't prepend non-integer"); | |
481 | ||
482 | res.type = T_PATH; | |
483 | res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i); | |
484 | break; | |
485 | ||
9c400ec9 PM |
486 | case P('C','a'): /* Community list add or delete */ |
487 | TWOARGS; | |
488 | if (v1.type != T_CLIST) | |
489 | runtime("Can't add/delete to non-clist"); | |
490 | if (v2.type != T_PAIR) | |
491 | runtime("Can't add/delete non-pair"); | |
492 | ||
493 | res.type = T_CLIST; | |
494 | switch (what->aux) { | |
495 | case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break; | |
496 | case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break; | |
497 | default: bug("unknown Ca operation"); | |
498 | } | |
499 | break; | |
500 | ||
23b1539b PM |
501 | default: |
502 | bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); | |
503 | } | |
504 | if (what->next) | |
505 | return interpret(what->next); | |
506 | return res; | |
507 | } | |
508 | ||
2d496d20 | 509 | #undef ARG |
9a4037d4 PM |
510 | #define ARG(x,y) \ |
511 | if (!i_same(f1->y, f2->y)) \ | |
512 | return 0; | |
513 | ||
514 | #define ONEARG ARG(v1, a1.p) | |
515 | #define TWOARGS ARG(v1, a1.p) \ | |
516 | ARG(v2, a2.p) | |
517 | ||
518 | #define A2_SAME if (f1->a2.i != f2->a2.i) return 0; | |
519 | ||
520 | int | |
521 | i_same(struct f_inst *f1, struct f_inst *f2) | |
522 | { | |
9a4037d4 PM |
523 | if ((!!f1) != (!!f2)) |
524 | return 0; | |
d4d75628 PM |
525 | if (!f1) |
526 | return 1; | |
9a4037d4 PM |
527 | if (f1->aux != f2->aux) |
528 | return 0; | |
529 | if (f1->code != f2->code) | |
530 | return 0; | |
d4d75628 PM |
531 | if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ |
532 | return 1; | |
9a4037d4 PM |
533 | |
534 | switch(f1->code) { | |
535 | case ',': /* fall through */ | |
536 | case '+': | |
537 | case '/': | |
2d496d20 PM |
538 | case P('!','='): |
539 | case P('=','='): | |
9a4037d4 | 540 | case '<': |
2d496d20 | 541 | case P('<','='): TWOARGS; break; |
9a4037d4 | 542 | |
995e5894 | 543 | case '!': ONEARG; break; |
9a4037d4 | 544 | case '~': TWOARGS; break; |
2d496d20 | 545 | case P('d','e'): ONEARG; break; |
9a4037d4 PM |
546 | |
547 | case 's': | |
548 | ARG(v2, a2.p); | |
549 | { | |
550 | struct symbol *s1, *s2; | |
551 | s1 = f1->a1.p; | |
552 | s2 = f2->a1.p; | |
553 | if (strcmp(s1->name, s2->name)) | |
554 | return 0; | |
555 | if (s1->class != s2->class) | |
556 | return 0; | |
557 | } | |
558 | break; | |
559 | ||
560 | case 'c': A2_SAME; break; | |
561 | case 'C': | |
562 | if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a2.p)) | |
563 | return 0; | |
564 | break; | |
684c6f5a | 565 | case 'p': case 'L': ONEARG; break; |
9a4037d4 | 566 | case '?': TWOARGS; break; |
afc54517 | 567 | case '0': case 'E': break; |
2d496d20 | 568 | case P('p',','): ONEARG; A2_SAME; break; |
9a4037d4 | 569 | case 'a': A2_SAME; break; |
2d496d20 PM |
570 | case P('e','a'): A2_SAME; break; |
571 | case P('e','S'): ONEARG; A2_SAME; break; | |
9a4037d4 | 572 | |
2d496d20 PM |
573 | case 'r': ONEARG; break; |
574 | case P('c','p'): ONEARG; break; | |
d4d75628 PM |
575 | case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ |
576 | ONEARG; | |
577 | if (!i_same(f1->a2.p, f2->a2.p)) | |
578 | return 0; | |
579 | f2->a2.p = f1->a2.p; | |
580 | break; | |
2d496d20 PM |
581 | case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; |
582 | case P('i','M'): TWOARGS; break; | |
afc54517 | 583 | case P('A','p'): TWOARGS; break; |
9c400ec9 | 584 | case P('C','a'): TWOARGS; break; |
9a4037d4 PM |
585 | default: |
586 | bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); | |
587 | } | |
588 | return i_same(f1->next, f2->next); | |
589 | } | |
590 | ||
23b1539b | 591 | int |
0a06a9b8 | 592 | f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags) |
23b1539b PM |
593 | { |
594 | struct f_inst *inst; | |
595 | struct f_val res; | |
6b9fa320 | 596 | DBG( "Running filter `%s'...", filter->name ); |
23b1539b | 597 | |
0a06a9b8 | 598 | f_flags = flags; |
31e79264 | 599 | f_tmp_attrs = tmp_attrs; |
36bbfc70 | 600 | f_rte = rte; |
48f9e019 | 601 | f_rte_old = *rte; |
f31156ca | 602 | f_pool = tmp_pool; |
23b1539b PM |
603 | inst = filter->root; |
604 | res = interpret(inst); | |
605 | if (res.type != T_RETURN) | |
606 | return F_ERROR; | |
6b9fa320 | 607 | DBG( "done (%d)\n", res.val.i ); |
23b1539b PM |
608 | return res.val.i; |
609 | } | |
610 | ||
23b1539b PM |
611 | void |
612 | filters_postconfig(void) | |
613 | { | |
614 | struct f_val res; | |
8ba2cc06 | 615 | if (startup_func) { |
3cf4a2e2 | 616 | debug( "Launching startup function...\n" ); |
e399b6f6 | 617 | f_pool = lp_new(&root_pool, 1024); |
23b1539b | 618 | res = interpret(startup_func); |
bad631e0 | 619 | if (res.type == F_ERROR) |
8ba2cc06 | 620 | die( "Startup function resulted in error." ); |
3cf4a2e2 | 621 | debug( "done\n" ); |
8ba2cc06 | 622 | } |
23b1539b | 623 | } |
30a6108c MM |
624 | |
625 | int | |
626 | filter_same(struct filter *new, struct filter *old) | |
627 | { | |
81ce667b MM |
628 | if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */ |
629 | return 1; | |
630 | if (old == FILTER_ACCEPT || old == FILTER_REJECT || | |
631 | new == FILTER_ACCEPT || new == FILTER_REJECT) | |
632 | return 0; | |
9a4037d4 | 633 | return i_same(new->root, old->root); |
30a6108c | 634 | } |
7f77e250 | 635 | |
9196e9f8 | 636 | /* This should end up far away from here! |
9196e9f8 | 637 | */ |
7f77e250 PM |
638 | struct adata * |
639 | comlist_add(struct linpool *pool, struct adata *list, u32 val) | |
640 | { | |
641 | struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4); | |
642 | res->length = list->length+4; | |
643 | * (u32 *) res->data = val; | |
644 | memcpy((char *) res->data + 4, list->data, list->length); | |
645 | return res; | |
646 | } | |
647 | ||
648 | struct adata * | |
649 | comlist_contains(struct adata *list, u32 val) | |
650 | { | |
651 | u32 *l = &(list->data); | |
652 | int i; | |
653 | for (i=0; i<list->length/4; i++) | |
654 | if (*l++ == val) | |
655 | return 1; | |
656 | return 0; | |
657 | } | |
658 | ||
659 | struct adata * | |
660 | comlist_del(struct linpool *pool, struct adata *list, u32 val) | |
661 | { | |
662 | struct adata *res; | |
663 | u32 *l, *k; | |
664 | int i; | |
665 | ||
666 | if (!comlist_contains(list, val)) | |
667 | return list; | |
668 | ||
669 | res = lp_alloc(pool, list->length + sizeof(struct adata) - 4); | |
670 | res->length = list->length-4; | |
671 | ||
672 | l = &(list->data); | |
673 | k = &(res->data); | |
674 | for (i=0; i<list->length/4; i++) | |
675 | if (l[i] != val) | |
676 | *k++ = l[i]; | |
677 | ||
678 | return res; | |
679 | } | |
680 | ||
681 | struct adata * | |
0a40e973 | 682 | adata_empty(struct linpool *pool) |
7f77e250 PM |
683 | { |
684 | struct adata *res = lp_alloc(pool, sizeof(struct adata)); | |
685 | res->length = 0; | |
686 | return res; | |
687 | } |