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