]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
You should not follow next two times.
[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
PM
7 *
8 * FIXME: local namespace for functions
720d911d
PM
9 *
10 * Notice that pair is stored as integer: first << 16 | second
23b1539b
PM
11 */
12
13#include <stdio.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <sys/signal.h>
17#include <setjmp.h>
18
19#include "nest/bird.h"
20#include "lib/lists.h"
21#include "lib/resource.h"
22#include "lib/socket.h"
38506f71 23#include "lib/string.h"
23b1539b
PM
24#include "nest/route.h"
25#include "nest/protocol.h"
26#include "nest/iface.h"
27#include "conf/conf.h"
28#include "filter/filter.h"
29
30struct f_inst *startup_func = NULL;
31
32#define runtime(x) do { \
33 log( L_ERR x ); \
34 res.type = T_RETURN; \
35 res.val.i = F_ERROR; \
36 return res; \
37 } while(0)
38
39#define ARG(x,y) \
40 x = interpret(what->y); \
41 if (x.type == T_RETURN) \
42 return x;
43
2db3b288
PM
44#define ONEARG ARG(v1, a1.p)
45#define TWOARGS ARG(v1, a1.p) \
46 ARG(v2, a2.p)
23b1539b
PM
47#define TWOARGS_C TWOARGS \
48 if (v1.type != v2.type) \
49 runtime( "Can not operate with values of incompatible types" );
50
38506f71
PM
51#define CMP_ERROR 999
52
53/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
54int
55val_compare(struct f_val v1, struct f_val v2)
56{
41be4444
PM
57 if ((v1.type == T_VOID) && (v2.type == T_VOID))
58 return 0;
59 if (v1.type == T_VOID) /* Hack for else */
60 return -1;
61 if (v2.type == T_VOID)
62 return 1;
63
7db7b7db
PM
64 if (v1.type != v2.type)
65 return CMP_ERROR;
38506f71
PM
66 switch (v1.type) {
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
PM
72 case T_IP:
73 return ipa_compare(v1.val.ip, v2.val.ip);
41be4444 74 default: { printf( "Error comparing\n" ); return CMP_ERROR; }
38506f71
PM
75 }
76}
77
7db7b7db
PM
78int
79val_in_range(struct f_val v1, struct f_val v2)
80{
81 if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET))
82 return !! find_tree(v2.val.t, v1);
83 return CMP_ERROR;
84}
85
38506f71
PM
86static void
87tree_print(struct f_tree *t)
88{
89 if (!t) {
90 printf( "() " );
91 return;
92 }
93 printf( "[ " );
94 tree_print( t->left );
95 printf( ", " ); val_print( t->from ); printf( ".." ); val_print( t->to ); printf( ", " );
96 tree_print( t->right );
97 printf( "] " );
98}
99
100void
101val_print(struct f_val v)
102{
103 char buf[2048];
104#define PRINTF(a...) bsnprintf( buf, 2040, a )
105 buf[0] = 0;
106 switch (v.type) {
107 case T_VOID: PRINTF( "(void)" ); break;
108 case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
109 case T_INT: PRINTF( "%d ", v.val.i ); break;
110 case T_STRING: PRINTF( "%s", v.val.s ); break;
111 case T_IP: PRINTF( "%I", v.val.ip ); break;
720d911d
PM
112 case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
113 case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
38506f71
PM
114 case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
115 default: PRINTF( "[unknown type %x]", v.type );
116 }
117 printf( buf );
118}
119
36bbfc70
PM
120static struct rte **f_rte;
121
7db7b7db
PM
122static struct f_val interpret(struct f_inst *what);
123
23b1539b
PM
124static struct f_val
125interpret(struct f_inst *what)
126{
127 struct symbol *sym;
128 struct f_val v1, v2, res;
38506f71 129 int i,j,k;
23b1539b
PM
130
131 res.type = T_VOID;
132 if (!what)
133 return res;
134
135 switch(what->code) {
136 case ',':
137 TWOARGS;
138 break;
139
140/* Binary operators */
141 case '+':
142 TWOARGS_C;
143 switch (res.type = v1.type) {
144 case T_VOID: runtime( "Can not operate with values of type void" );
145 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
146 default: runtime( "Usage of unknown type" );
147 }
148 break;
149 case '/':
150 TWOARGS_C;
151 switch (res.type = v1.type) {
152 case T_VOID: runtime( "Can not operate with values of type void" );
153 case T_INT: res.val.i = v1.val.i / v2.val.i; break;
154 case T_IP: if (v2.type != T_INT)
155 runtime( "Operator / is <ip>/<int>" );
156 break;
157 default: runtime( "Usage of unknown type" );
158 }
159 break;
160
161/* Relational operators */
38506f71
PM
162
163#define COMPARE(x) \
164 TWOARGS_C; \
165 res.type = T_BOOL; \
166 i = val_compare(v1, v2); \
167 if (i==CMP_ERROR) \
168 runtime( "Error in comparation" ); \
169 res.val.i = (x); \
23b1539b 170 break;
38506f71
PM
171
172 case '!=': COMPARE(i!=0);
173 case '==': COMPARE(i==0);
174 case '<': COMPARE(i==-1);
175 case '<=': COMPARE(i!=1);
176
29818140 177 /* FIXME: Should be able to work with prefixes of limited sizes */
38506f71
PM
178 case '~':
179 TWOARGS;
23b1539b 180 res.type = T_BOOL;
7db7b7db
PM
181 res.val.i = val_in_range(v1, v2);
182 if (res.val.i == CMP_ERROR)
183 runtime( "~ applied on unknown type pair" );
23b1539b
PM
184 break;
185
d3dd620b 186 /* Set to indirect value, a1 = variable, a2 = value */
23b1539b 187 case 's':
2db3b288
PM
188 ARG(v2, a2.p);
189 sym = what->a1.p;
23b1539b
PM
190 switch (res.type = v2.type) {
191 case T_VOID: runtime( "Can not assign void values" );
192 case T_INT:
d3dd620b
PM
193 case T_IP:
194 case T_PREFIX:
195 case T_PAIR:
196 if (sym->class != (SYM_VARIABLE | v2.type))
23b1539b 197 runtime( "Variable of bad type" );
d3dd620b 198 * (struct f_val *) sym->aux2 = v2;
23b1539b 199 break;
d3dd620b
PM
200 default:
201 bug( "Set to invalid type\n" );
23b1539b
PM
202 }
203 break;
204
d3dd620b 205 case 'c': /* integer (or simple type) constant */
2db3b288 206 res.type = what->a1.i;
d3dd620b 207 res.val.i = what->a2.i;
23b1539b 208 break;
38506f71
PM
209 case 'C':
210 res = * ((struct f_val *) what->a1.p);
211 break;
23b1539b
PM
212 case 'p':
213 ONEARG;
38506f71 214 val_print(v1);
23b1539b
PM
215 break;
216 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
217 ONEARG;
218 if (v1.type != T_BOOL)
219 runtime( "If requires bool expression" );
220 if (v1.val.i) {
2db3b288 221 ARG(res,a2.p);
23b1539b
PM
222 res.val.i = 0;
223 } else res.val.i = 1;
224 res.type = T_BOOL;
225 break;
226 case '0':
227 printf( "No operation\n" );
228 break;
229 case 'p,':
230 ONEARG;
d3dd620b
PM
231 if (what->a2.i != F_NONL)
232 printf( "\n" );
23b1539b 233
2db3b288 234 switch (what->a2.i) {
23b1539b
PM
235 case F_QUITBIRD:
236 die( "Filter asked me to die" );
237 case F_ACCEPT:
238 /* Should take care about turning ACCEPT into MODIFY */
239 case F_ERROR:
240 case F_REJECT:
241 res.type = T_RETURN;
2db3b288 242 res.val.i = what->a1.i;
23b1539b 243 break;
d3dd620b 244 case F_NONL:
23b1539b
PM
245 case F_NOP:
246 break;
247 default:
248 bug( "unknown return type: can not happen");
249 }
250 break;
36bbfc70
PM
251 case 'a': /* rta access */
252 {
253 struct rta *rta = (*f_rte)->attrs;
254 res.type = what->a1.i;
255 switch(res.type) {
256 case T_IP:
257 res.val.ip = * (ip_addr *) ((char *) rta + what->a2.i);
258 break;
259 case T_PREFIX: /* Warning: this works only for prefix of network */
260 {
261 res.val.px.ip = (*f_rte)->net->n.prefix;
262 res.val.px.len = (*f_rte)->net->n.pxlen;
263 break;
264 }
265 default:
266 bug( "Invalid type for rta access" );
267 }
268 }
269 break;
270 case 'cp': /* Convert prefix to ... */
271 ONEARG;
272 if (v1.type != T_PREFIX)
273 runtime( "Can not convert non-prefix this way" );
274 res.type = what->a2.i;
275 switch(res.type) {
276 case T_INT: res.val.i = v1.val.px.len; break;
277 case T_IP: res.val.ip = v1.val.px.ip; break;
278 default: bug( "Unknown prefix to conversion\n" );
279 }
280 break;
6542ece9
PM
281 case 'ca': /* CALL */
282 ONEARG;
283 res = interpret(what->a2.p);
284 break;
41be4444 285 case 'SW':
7db7b7db 286 ONEARG;
41be4444
PM
287 {
288 struct f_tree *t = find_tree(what->a2.p, v1);
289 if (!t) {
290 v1.type = T_VOID;
291 t = find_tree(what->a2.p, v1);
292 if (!t) {
293 printf( "No else statement?\n ");
294 break;
295 }
296 }
297 if (!t->data)
298 die( "Impossible: no code associated!\n" );
299 return interpret(t->data);
300 }
7db7b7db 301 break;
d3dd620b
PM
302 case 'iM': /* IP.MASK(val) */
303 TWOARGS_C;
304 bug( "Should implement ip.mask\n" );
305 break;
23b1539b
PM
306 default:
307 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
308 }
309 if (what->next)
310 return interpret(what->next);
311 return res;
312}
313
314int
315f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool)
316{
317 struct f_inst *inst;
318 struct f_val res;
319 debug( "Running filter `%s'...", filter->name );
320
36bbfc70 321 f_rte = rte;
23b1539b
PM
322 inst = filter->root;
323 res = interpret(inst);
324 if (res.type != T_RETURN)
325 return F_ERROR;
326 debug( "done (%d)\n", res.val.i );
327 return res.val.i;
328}
329
330
331void
332filters_postconfig(void)
333{
334 struct f_val res;
8ba2cc06
PM
335 if (startup_func) {
336 printf( "Launching startup function...\n" );
23b1539b 337 res = interpret(startup_func);
bad631e0 338 if (res.type == F_ERROR)
8ba2cc06
PM
339 die( "Startup function resulted in error." );
340 printf( "done\n" );
341 }
23b1539b 342}