1: /*
2: * Filters: Instructions themselves
3: *
4: * Copyright 1998 Pavel Machek <pavel@ucw.cz>
5: * Copyright 2018 Maria Matejka <mq@jmq.cz>
6: * Copyright 2018 CZ.NIC z.s.p.o.
7: *
8: * Can be freely distributed and used under the terms of the GNU GPL.
9: *
10: * The filter code goes through several phases:
11: *
12: * 1 Parsing
13: * Flex- and Bison-generated parser decodes the human-readable data into
14: * a struct f_inst tree. This is an infix tree that was interpreted by
15: * depth-first search execution in previous versions of the interpreter.
16: * All instructions have their constructor: f_new_inst(FI_EXAMPLE, ...)
17: * translates into f_new_inst_FI_EXAMPLE(...) and the types are checked in
18: * compile time. If the result of the instruction is always the same,
19: * it's reduced to FI_CONSTANT directly in constructor. This phase also
20: * counts how many instructions are underlying in means of f_line_item
21: * fields to know how much we have to allocate in the next phase.
22: *
23: * 2 Linearize before interpreting
24: * The infix tree is always interpreted in the same order. Therefore we
25: * sort the instructions one after another into struct f_line. Results
26: * and arguments of these instructions are implicitly put on a value
27: * stack; e.g. the + operation just takes two arguments from the value
28: * stack and puts the result on there.
29: *
30: * 3 Interpret
31: * The given line is put on a custom execution stack. If needed (FI_CALL,
32: * FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top
33: * of the stack; when that line finishes, the execution continues on the
34: * older lines on the stack where it stopped before.
35: *
36: * 4 Same
37: * On config reload, the filters have to be compared whether channel
38: * reload is needed or not. The comparison is done by comparing the
39: * struct f_line's recursively.
40: *
41: * The main purpose of this rework was to improve filter performance
42: * by making the interpreter non-recursive.
43: *
44: * The other outcome is concentration of instruction definitions to
45: * one place -- right here. You shall define your instruction only here
46: * and nowhere else.
47: *
48: * Beware. This file is interpreted by M4 macros. These macros
49: * may be more stupid than you could imagine. If something strange
50: * happens after changing this file, compare the results before and
51: * after your change (see the Makefile to find out where the results are)
52: * and see what really happened.
53: *
54: * This file is not directly a C source code -> it is a generator input
55: * for several C sources; every instruction block gets expanded into many
56: * different places.
57: *
58: * All the arguments are processed literally; if you need an argument including comma,
59: * you have to quote it by [[ ... ]]
60: *
61: * What is the syntax here?
62: * m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args
63: * m4_dnl ARG(num, type); argument, its id (in data fields) and type accessible by v1, v2, v3
64: * m4_dnl ARG_ANY(num); argument with no type check accessible by v1, v2, v3
65: * m4_dnl VARARG; variable-length argument list; accessible by vv(i) and whati->varcount
66: * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line
67: * m4_dnl SYMBOL; symbol handed from config
68: * m4_dnl STATIC_ATTR; static attribute definition
69: * m4_dnl DYNAMIC_ATTR; dynamic attribute definition
70: * m4_dnl RTC; route table config
71: * m4_dnl ACCESS_RTE; this instruction needs route
72: * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes
73: *
74: * m4_dnl FID_MEMBER( custom instruction member
75: * m4_dnl C type, for storage in structs
76: * m4_dnl name, how the member is named
77: * m4_dnl comparator for same(), if different, this should be TRUE (CAVEAT)
78: * m4_dnl dump format string debug -> format string for bvsnprintf
79: * m4_dnl dump format args appropriate args
80: * m4_dnl )
81: *
82: * m4_dnl RESULT(type, union-field, value); putting this on value stack
83: * m4_dnl RESULT_VAL(value-struct); pass the struct f_val directly
84: * m4_dnl RESULT_VOID; return undef
85: * m4_dnl }
86: *
87: * Also note that the { ... } blocks are not respected by M4 at all.
88: * If you get weird unmatched-brace-pair errors, check what it generated and why.
89: * What is really considered as one instruction is not the { ... } block
90: * after m4_dnl INST() but all the code between them.
91: *
92: * Other code is just copied into the interpreter part.
93: *
94: * If you are satisfied with this, you don't need to read the following
95: * detailed description of what is really done with the instruction definitions.
96: *
97: * m4_dnl Now let's look under the cover. The code between each INST()
98: * m4_dnl is copied to several places, namely these (numbered by the M4 diversions
99: * m4_dnl used in filter/decl.m4):
100: *
101: * m4_dnl (102) struct f_inst *f_new_inst(FI_EXAMPLE [[ put it here ]])
102: * m4_dnl {
103: * m4_dnl ... (common code)
104: * m4_dnl (103) [[ put it here ]]
105: * m4_dnl ...
106: * m4_dnl if (all arguments are constant)
107: * m4_dnl (108) [[ put it here ]]
108: * m4_dnl }
109: * m4_dnl For writing directly to constructor argument list, use FID_NEW_ARGS.
110: * m4_dnl For computing something in constructor (103), use FID_NEW_BODY.
111: * m4_dnl For constant pre-interpretation (108), see below at FID_INTERPRET_BODY.
112: *
113: * m4_dnl struct f_inst {
114: * m4_dnl ... (common fields)
115: * m4_dnl union {
116: * m4_dnl struct {
117: * m4_dnl (101) [[ put it here ]]
118: * m4_dnl } i_FI_EXAMPLE;
119: * m4_dnl ...
120: * m4_dnl };
121: * m4_dnl };
122: * m4_dnl This structure is returned from constructor.
123: * m4_dnl For writing directly to this structure, use FID_STRUCT_IN.
124: *
125: * m4_dnl linearize(struct f_line *dest, const struct f_inst *what, uint pos) {
126: * m4_dnl ...
127: * m4_dnl switch (what->fi_code) {
128: * m4_dnl case FI_EXAMPLE:
129: * m4_dnl (105) [[ put it here ]]
130: * m4_dnl break;
131: * m4_dnl }
132: * m4_dnl }
133: * m4_dnl This is called when translating from struct f_inst to struct f_line_item.
134: * m4_dnl For accessing your custom instruction data, use following macros:
135: * m4_dnl whati -> for accessing (struct f_inst).i_FI_EXAMPLE
136: * m4_dnl item -> for accessing (struct f_line)[pos].i_FI_EXAMPLE
137: * m4_dnl For writing directly here, use FID_LINEARIZE_BODY.
138: *
139: * m4_dnl (107) struct f_line_item {
140: * m4_dnl ... (common fields)
141: * m4_dnl union {
142: * m4_dnl struct {
143: * m4_dnl (101) [[ put it here ]]
144: * m4_dnl } i_FI_EXAMPLE;
145: * m4_dnl ...
146: * m4_dnl };
147: * m4_dnl };
148: * m4_dnl The same as FID_STRUCT_IN (101) but for the other structure.
149: * m4_dnl This structure is returned from the linearizer (105).
150: * m4_dnl For writing directly to this structure, use FID_LINE_IN.
151: *
152: * m4_dnl f_dump_line_item_FI_EXAMPLE(const struct f_line_item *item, const int indent)
153: * m4_dnl {
154: * m4_dnl (104) [[ put it here ]]
155: * m4_dnl }
156: * m4_dnl This code dumps the instruction on debug. Note that the argument
157: * m4_dnl is the linearized instruction; if the instruction has arguments,
158: * m4_dnl their code has already been linearized and their value is taken
159: * m4_dnl from the value stack.
160: * m4_dnl For writing directly here, use FID_DUMP_BODY.
161: *
162: * m4_dnl f_same(...)
163: * m4_dnl {
164: * m4_dnl switch (f1_->fi_code) {
165: * m4_dnl case FI_EXAMPLE:
166: * m4_dnl (106) [[ put it here ]]
167: * m4_dnl break;
168: * m4_dnl }
169: * m4_dnl }
170: * m4_dnl This code compares the two given instrucions (f1_ and f2_)
171: * m4_dnl on reconfigure. For accessing your custom instruction data,
172: * m4_dnl use macros f1 and f2.
173: * m4_dnl For writing directly here, use FID_SAME_BODY.
174: *
175: * m4_dnl interpret(...)
176: * m4_dnl {
177: * m4_dnl switch (what->fi_code) {
178: * m4_dnl case FI_EXAMPLE:
179: * m4_dnl (108) [[ put it here ]]
180: * m4_dnl break;
181: * m4_dnl }
182: * m4_dnl }
183: * m4_dnl This code executes the instruction. Every pre-defined macro
184: * m4_dnl resets the output here. For setting it explicitly,
185: * m4_dnl use FID_INTERPRET_BODY.
186: * m4_dnl This code is put on two places; one is the interpreter, the other
187: * m4_dnl is instruction constructor. If you need to distinguish between
188: * m4_dnl these two, use FID_INTERPRET_EXEC or FID_INTERPRET_NEW respectively.
189: * m4_dnl To address the difference between interpreter and constructor
190: * m4_dnl environments, there are several convenience macros defined:
191: * m4_dnl runtime() -> for spitting out runtime error like division by zero
192: * m4_dnl RESULT(...) -> declare result; may overwrite arguments
193: * m4_dnl v1, v2, v3 -> positional arguments, may be overwritten by RESULT()
194: * m4_dnl falloc(size) -> allocate memory from the appropriate linpool
195: * m4_dnl fpool -> the current linpool
196: * m4_dnl NEVER_CONSTANT-> don't generate pre-interpretation code at all
197: * m4_dnl ACCESS_RTE -> check that route is available, also NEVER_CONSTANT
198: * m4_dnl ACCESS_EATTRS -> pre-cache the eattrs; use only with ACCESS_RTE
199: * m4_dnl f_rta_cow(fs) -> function to call before any change to route should be done
200: *
201: * m4_dnl If you are stymied, see FI_CALL or FI_CONSTANT or just search for
202: * m4_dnl the mentioned macros in this file to see what is happening there in wild.
203: */
204:
205: /* Binary operators */
206: INST(FI_ADD, 2, 1) {
207: ARG(1,T_INT);
208: ARG(2,T_INT);
209: RESULT(T_INT, i, v1.val.i + v2.val.i);
210: }
211: INST(FI_SUBTRACT, 2, 1) {
212: ARG(1,T_INT);
213: ARG(2,T_INT);
214: RESULT(T_INT, i, v1.val.i - v2.val.i);
215: }
216: INST(FI_MULTIPLY, 2, 1) {
217: ARG(1,T_INT);
218: ARG(2,T_INT);
219: RESULT(T_INT, i, v1.val.i * v2.val.i);
220: }
221: INST(FI_DIVIDE, 2, 1) {
222: ARG(1,T_INT);
223: ARG(2,T_INT);
224: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
225: RESULT(T_INT, i, v1.val.i / v2.val.i);
226: }
227: INST(FI_AND, 1, 1) {
228: ARG(1,T_BOOL);
229: if (v1.val.i)
230: LINE(2,0);
231: else
232: RESULT_VAL(v1);
233: }
234: INST(FI_OR, 1, 1) {
235: ARG(1,T_BOOL);
236: if (!v1.val.i)
237: LINE(2,0);
238: else
239: RESULT_VAL(v1);
240: }
241:
242: INST(FI_PAIR_CONSTRUCT, 2, 1) {
243: ARG(1,T_INT);
244: ARG(2,T_INT);
245: uint u1 = v1.val.i;
246: uint u2 = v2.val.i;
247: if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
248: runtime( "Can't operate with value out of bounds in pair constructor" );
249: RESULT(T_PAIR, i, (u1 << 16) | u2);
250: }
251:
252: INST(FI_EC_CONSTRUCT, 2, 1) {
253: ARG_ANY(1);
254: ARG(2, T_INT);
255:
256: FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, "ec subtype %s", ec_subtype_str(item->ecs));
257:
258: int check, ipv4_used;
259: u32 key, val;
260:
261: if (v1.type == T_INT) {
262: ipv4_used = 0; key = v1.val.i;
263: }
264: else if (v1.type == T_QUAD) {
265: ipv4_used = 1; key = v1.val.i;
266: }
267: /* IP->Quad implicit conversion */
268: else if (val_is_ip4(&v1)) {
269: ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
270: }
271: else
272: runtime("Argument 1 of EC constructor must be integer or IPv4 address, got 0x%02x", v1.type);
273:
274: val = v2.val.i;
275:
276: if (ecs == EC_GENERIC) {
277: check = 0; RESULT(T_EC, ec, ec_generic(key, val));
278: }
279: else if (ipv4_used) {
280: check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
281: }
282: else if (key < 0x10000) {
283: check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
284: }
285: else {
286: check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
287: }
288:
289: if (check && (val > 0xFFFF))
290: runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
291: }
292:
293: INST(FI_LC_CONSTRUCT, 3, 1) {
294: ARG(1, T_INT);
295: ARG(2, T_INT);
296: ARG(3, T_INT);
297: RESULT(T_LC, lc, [[(lcomm) { v1.val.i, v2.val.i, v3.val.i }]]);
298: }
299:
300: INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
301: VARARG;
302:
303: struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->varcount * sizeof(struct f_path_mask_item));
304: pm->len = whati->varcount;
305:
306: for (uint i=0; i<whati->varcount; i++) {
307: switch (vv(i).type) {
308: case T_PATH_MASK_ITEM:
309: pm->item[i] = vv(i).val.pmi;
310: break;
311:
312: case T_INT:
313: pm->item[i] = (struct f_path_mask_item) {
314: .asn = vv(i).val.i,
315: .kind = PM_ASN,
316: };
317: break;
318:
319: case T_SET:
320: if (vv(i).val.t->from.type != T_INT)
321: runtime("Only integer sets allowed in path mask");
322:
323: pm->item[i] = (struct f_path_mask_item) {
324: .set = vv(i).val.t,
325: .kind = PM_ASN_SET,
326: };
327: break;
328:
329: default:
330: runtime( "Error resolving path mask template: value not an integer" );
331: }
332: }
333:
334: RESULT(T_PATH_MASK, path_mask, pm);
335: }
336:
337: /* Relational operators */
338:
339: INST(FI_NEQ, 2, 1) {
340: ARG_ANY(1);
341: ARG_ANY(2);
342: RESULT(T_BOOL, i, !val_same(&v1, &v2));
343: }
344:
345: INST(FI_EQ, 2, 1) {
346: ARG_ANY(1);
347: ARG_ANY(2);
348: RESULT(T_BOOL, i, val_same(&v1, &v2));
349: }
350:
351: INST(FI_LT, 2, 1) {
352: ARG_ANY(1);
353: ARG_ANY(2);
354: int i = val_compare(&v1, &v2);
355: if (i == F_CMP_ERROR)
356: runtime( "Can't compare values of incompatible types" );
357: RESULT(T_BOOL, i, (i == -1));
358: }
359:
360: INST(FI_LTE, 2, 1) {
361: ARG_ANY(1);
362: ARG_ANY(2);
363: int i = val_compare(&v1, &v2);
364: if (i == F_CMP_ERROR)
365: runtime( "Can't compare values of incompatible types" );
366: RESULT(T_BOOL, i, (i != 1));
367: }
368:
369: INST(FI_NOT, 1, 1) {
370: ARG(1,T_BOOL);
371: RESULT(T_BOOL, i, !v1.val.i);
372: }
373:
374: INST(FI_MATCH, 2, 1) {
375: ARG_ANY(1);
376: ARG_ANY(2);
377: int i = val_in_range(&v1, &v2);
378: if (i == F_CMP_ERROR)
379: runtime( "~ applied on unknown type pair" );
380: RESULT(T_BOOL, i, !!i);
381: }
382:
383: INST(FI_NOT_MATCH, 2, 1) {
384: ARG_ANY(1);
385: ARG_ANY(2);
386: int i = val_in_range(&v1, &v2);
387: if (i == F_CMP_ERROR)
388: runtime( "!~ applied on unknown type pair" );
389: RESULT(T_BOOL, i, !i);
390: }
391:
392: INST(FI_DEFINED, 1, 1) {
393: ARG_ANY(1);
394: RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
395: }
396:
397: INST(FI_TYPE, 1, 1) {
398: ARG_ANY(1); /* There may be more types supporting this operation */
399: switch (v1.type)
400: {
401: case T_NET:
402: RESULT(T_ENUM_NETTYPE, i, v1.val.net->type);
403: break;
404: default:
405: runtime( "Can't determine type of this item" );
406: }
407: }
408:
409: INST(FI_IS_V4, 1, 1) {
410: ARG(1, T_IP);
411: RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip));
412: }
413:
414: /* Set to indirect value prepared in v1 */
415: INST(FI_VAR_SET, 1, 0) {
416: NEVER_CONSTANT;
417: ARG_ANY(1);
418: SYMBOL;
419:
420: if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
421: {
422: /* IP->Quad implicit conversion */
423: if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
424: v1 = (struct f_val) {
425: .type = T_QUAD,
426: .val.i = ipa_to_u32(v1.val.ip),
427: };
428: else
429: runtime( "Assigning to variable of incompatible type" );
430: }
431:
432: fstk->vstk[curline.vbase + sym->offset] = v1;
433: }
434:
435: INST(FI_VAR_GET, 0, 1) {
436: SYMBOL;
437: NEVER_CONSTANT;
438: RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
439: }
440:
441: INST(FI_CONSTANT, 0, 1) {
442: FID_MEMBER(
443: struct f_val,
444: val,
445: [[ !val_same(&(f1->val), &(f2->val)) ]],
446: "value %s",
447: val_dump(&(item->val))
448: );
449:
450: RESULT_VAL(val);
451: }
452:
453: INST(FI_CONDITION, 1, 0) {
454: ARG(1, T_BOOL);
455: if (v1.val.i)
456: LINE(2,0);
457: else
458: LINE(3,1);
459: }
460:
461: INST(FI_PRINT, 0, 0) {
462: NEVER_CONSTANT;
463: VARARG;
464:
465: if (whati->varcount && !(fs->flags & FF_SILENT))
466: for (uint i=0; i<whati->varcount; i++)
467: val_format(&(vv(i)), &fs->buf);
468: }
469:
470: INST(FI_FLUSH, 0, 0) {
471: NEVER_CONSTANT;
472: if (!(fs->flags & FF_SILENT))
473: /* After log_commit, the buffer is reset */
474: log_commit(*L_INFO, &fs->buf);
475: }
476:
477: INST(FI_DIE, 0, 0) {
478: NEVER_CONSTANT;
479: FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, "%s", filter_return_str(item->fret));
480:
481: switch (whati->fret) {
482: case F_QUITBIRD:
483: die( "Filter asked me to die" );
484: case F_ACCEPT: /* Should take care about turning ACCEPT into MODIFY */
485: case F_ERROR:
486: case F_REJECT: /* Maybe print complete route along with reason to reject route? */
487: return fret; /* We have to return now, no more processing. */
488: default:
489: bug( "unknown return type: Can't happen");
490: }
491: }
492:
493: INST(FI_RTA_GET, 0, 1) {
494: {
495: STATIC_ATTR;
496: ACCESS_RTE;
497: struct rta *rta = (*fs->rte)->attrs;
498:
499: switch (sa.sa_code)
500: {
501: case SA_FROM: RESULT(sa.f_type, ip, rta->from); break;
502: case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break;
503: case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
504: case SA_PROTO: RESULT(sa.f_type, s, rta->src->proto->name); break;
505: case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break;
506: case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break;
507: case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
508: case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
509: case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
510:
511: default:
512: bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
513: }
514: }
515: }
516:
517: INST(FI_RTA_SET, 1, 0) {
518: ACCESS_RTE;
519: ARG_ANY(1);
520: STATIC_ATTR;
521: if (sa.f_type != v1.type)
522: runtime( "Attempt to set static attribute to incompatible type" );
523:
524: f_rta_cow(fs);
525: {
526: struct rta *rta = (*fs->rte)->attrs;
527:
528: switch (sa.sa_code)
529: {
530: case SA_FROM:
531: rta->from = v1.val.ip;
532: break;
533:
534: case SA_GW:
535: {
536: ip_addr ip = v1.val.ip;
537: neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
538: if (!n || (n->scope == SCOPE_HOST))
539: runtime( "Invalid gw address" );
540:
541: rta->dest = RTD_UNICAST;
542: rta->nh.gw = ip;
543: rta->nh.iface = n->iface;
544: rta->nh.next = NULL;
545: rta->hostentry = NULL;
546: }
547: break;
548:
549: case SA_SCOPE:
550: rta->scope = v1.val.i;
551: break;
552:
553: case SA_DEST:
554: {
555: int i = v1.val.i;
556: if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
557: runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
558:
559: rta->dest = i;
560: rta->nh.gw = IPA_NONE;
561: rta->nh.iface = NULL;
562: rta->nh.next = NULL;
563: rta->hostentry = NULL;
564: }
565: break;
566:
567: case SA_IFNAME:
568: {
569: struct iface *ifa = if_find_by_name(v1.val.s);
570: if (!ifa)
571: runtime( "Invalid iface name" );
572:
573: rta->dest = RTD_UNICAST;
574: rta->nh.gw = IPA_NONE;
575: rta->nh.iface = ifa;
576: rta->nh.next = NULL;
577: rta->hostentry = NULL;
578: }
579: break;
580:
581: default:
582: bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
583: }
584: }
585: }
586:
587: INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */
588: DYNAMIC_ATTR;
589: ACCESS_RTE;
590: ACCESS_EATTRS;
591: {
592: eattr *e = ea_find(*fs->eattrs, da.ea_code);
593:
594: if (!e) {
595: /* A special case: undefined as_path looks like empty as_path */
596: if (da.type == EAF_TYPE_AS_PATH) {
597: RESULT(T_PATH, ad, &null_adata);
598: break;
599: }
600:
601: /* The same special case for int_set */
602: if (da.type == EAF_TYPE_INT_SET) {
603: RESULT(T_CLIST, ad, &null_adata);
604: break;
605: }
606:
607: /* The same special case for ec_set */
608: if (da.type == EAF_TYPE_EC_SET) {
609: RESULT(T_ECLIST, ad, &null_adata);
610: break;
611: }
612:
613: /* The same special case for lc_set */
614: if (da.type == EAF_TYPE_LC_SET) {
615: RESULT(T_LCLIST, ad, &null_adata);
616: break;
617: }
618:
619: /* Undefined value */
620: RESULT_VOID;
621: break;
622: }
623:
624: switch (e->type & EAF_TYPE_MASK) {
625: case EAF_TYPE_INT:
626: RESULT(da.f_type, i, e->u.data);
627: break;
628: case EAF_TYPE_ROUTER_ID:
629: RESULT(T_QUAD, i, e->u.data);
630: break;
631: case EAF_TYPE_OPAQUE:
632: RESULT(T_ENUM_EMPTY, i, 0);
633: break;
634: case EAF_TYPE_IP_ADDRESS:
635: RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
636: break;
637: case EAF_TYPE_AS_PATH:
638: RESULT(T_PATH, ad, e->u.ptr);
639: break;
640: case EAF_TYPE_BITFIELD:
641: RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
642: break;
643: case EAF_TYPE_INT_SET:
644: RESULT(T_CLIST, ad, e->u.ptr);
645: break;
646: case EAF_TYPE_EC_SET:
647: RESULT(T_ECLIST, ad, e->u.ptr);
648: break;
649: case EAF_TYPE_LC_SET:
650: RESULT(T_LCLIST, ad, e->u.ptr);
651: break;
652: case EAF_TYPE_UNDEF:
653: RESULT_VOID;
654: break;
655: default:
656: bug("Unknown dynamic attribute type");
657: }
658: }
659: }
660:
661: INST(FI_EA_SET, 1, 0) {
662: ACCESS_RTE;
663: ACCESS_EATTRS;
664: ARG_ANY(1);
665: DYNAMIC_ATTR;
666: {
667: struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
668:
669: l->next = NULL;
670: l->flags = EALF_SORTED;
671: l->count = 1;
672: l->attrs[0].id = da.ea_code;
673: l->attrs[0].flags = 0;
674: l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
675:
676: switch (da.type) {
677: case EAF_TYPE_INT:
678: if (v1.type != da.f_type)
679: runtime( "Setting int attribute to non-int value" );
680: l->attrs[0].u.data = v1.val.i;
681: break;
682:
683: case EAF_TYPE_ROUTER_ID:
684: /* IP->Quad implicit conversion */
685: if (val_is_ip4(&v1)) {
686: l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
687: break;
688: }
689: /* T_INT for backward compatibility */
690: if ((v1.type != T_QUAD) && (v1.type != T_INT))
691: runtime( "Setting quad attribute to non-quad value" );
692: l->attrs[0].u.data = v1.val.i;
693: break;
694:
695: case EAF_TYPE_OPAQUE:
696: runtime( "Setting opaque attribute is not allowed" );
697: break;
698:
699: case EAF_TYPE_IP_ADDRESS:
700: if (v1.type != T_IP)
701: runtime( "Setting ip attribute to non-ip value" );
702: int len = sizeof(ip_addr);
703: struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
704: ad->length = len;
705: (* (ip_addr *) ad->data) = v1.val.ip;
706: l->attrs[0].u.ptr = ad;
707: break;
708:
709: case EAF_TYPE_AS_PATH:
710: if (v1.type != T_PATH)
711: runtime( "Setting path attribute to non-path value" );
712: l->attrs[0].u.ptr = v1.val.ad;
713: break;
714:
715: case EAF_TYPE_BITFIELD:
716: if (v1.type != T_BOOL)
717: runtime( "Setting bit in bitfield attribute to non-bool value" );
718: {
719: /* First, we have to find the old value */
720: eattr *e = ea_find(*fs->eattrs, da.ea_code);
721: u32 data = e ? e->u.data : 0;
722:
723: if (v1.val.i)
724: l->attrs[0].u.data = data | (1u << da.bit);
725: else
726: l->attrs[0].u.data = data & ~(1u << da.bit);
727: }
728: break;
729:
730: case EAF_TYPE_INT_SET:
731: if (v1.type != T_CLIST)
732: runtime( "Setting clist attribute to non-clist value" );
733: l->attrs[0].u.ptr = v1.val.ad;
734: break;
735:
736: case EAF_TYPE_EC_SET:
737: if (v1.type != T_ECLIST)
738: runtime( "Setting eclist attribute to non-eclist value" );
739: l->attrs[0].u.ptr = v1.val.ad;
740: break;
741:
742: case EAF_TYPE_LC_SET:
743: if (v1.type != T_LCLIST)
744: runtime( "Setting lclist attribute to non-lclist value" );
745: l->attrs[0].u.ptr = v1.val.ad;
746: break;
747:
748: default:
749: bug("Unknown dynamic attribute type");
750: }
751:
752: f_rta_cow(fs);
753: l->next = *fs->eattrs;
754: *fs->eattrs = l;
755: }
756: }
757:
758: INST(FI_EA_UNSET, 0, 0) {
759: DYNAMIC_ATTR;
760: ACCESS_RTE;
761: ACCESS_EATTRS;
762:
763: {
764: struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
765:
766: l->next = NULL;
767: l->flags = EALF_SORTED;
768: l->count = 1;
769: l->attrs[0].id = da.ea_code;
770: l->attrs[0].flags = 0;
771: l->attrs[0].type = EAF_TYPE_UNDEF | EAF_ORIGINATED | EAF_FRESH;
772: l->attrs[0].u.data = 0;
773:
774: f_rta_cow(fs);
775: l->next = *fs->eattrs;
776: *fs->eattrs = l;
777: }
778: }
779:
780: INST(FI_PREF_GET, 0, 1) {
781: ACCESS_RTE;
782: RESULT(T_INT, i, (*fs->rte)->pref);
783: }
784:
785: INST(FI_PREF_SET, 1, 0) {
786: ACCESS_RTE;
787: ARG(1,T_INT);
788: if (v1.val.i > 0xFFFF)
789: runtime( "Setting preference value out of bounds" );
790: f_rte_cow(fs);
791: (*fs->rte)->pref = v1.val.i;
792: }
793:
794: INST(FI_LENGTH, 1, 1) { /* Get length of */
795: ARG_ANY(1);
796: switch(v1.type) {
797: case T_NET: RESULT(T_INT, i, net_pxlen(v1.val.net)); break;
798: case T_PATH: RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break;
799: case T_CLIST: RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break;
800: case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break;
801: case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break;
802: default: runtime( "Prefix, path, clist or eclist expected" );
803: }
804: }
805:
806: INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */
807: ARG(1, T_NET);
808: if (!net_is_sadr(v1.val.net))
809: runtime( "SADR expected" );
810:
811: net_addr_ip6_sadr *net = (void *) v1.val.net;
812: net_addr *src = falloc(sizeof(net_addr_ip6));
813: net_fill_ip6(src, net->src_prefix, net->src_pxlen);
814:
815: RESULT(T_NET, net, src);
816: }
817:
818: INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
819: ARG(1, T_NET);
820: if (!net_is_roa(v1.val.net))
821: runtime( "ROA expected" );
822:
823: RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
824: ((net_addr_roa4 *) v1.val.net)->max_pxlen :
825: ((net_addr_roa6 *) v1.val.net)->max_pxlen);
826: }
827:
828: INST(FI_ROA_ASN, 1, 1) { /* Get ROA ASN */
829: ARG(1, T_NET);
830: if (!net_is_roa(v1.val.net))
831: runtime( "ROA expected" );
832:
833: RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
834: ((net_addr_roa4 *) v1.val.net)->asn :
835: ((net_addr_roa6 *) v1.val.net)->asn);
836: }
837:
838: INST(FI_IP, 1, 1) { /* Convert prefix to ... */
839: ARG(1, T_NET);
840: RESULT(T_IP, ip, net_prefix(v1.val.net));
841: }
842:
843: INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
844: ARG(1, T_NET);
845: if (!net_is_vpn(v1.val.net))
846: runtime( "VPN address expected" );
847: RESULT(T_RD, ec, net_rd(v1.val.net));
848: }
849:
850: INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */
851: ARG(1, T_PATH);
852: int as = 0;
853: as_path_get_first(v1.val.ad, &as);
854: RESULT(T_INT, i, as);
855: }
856:
857: INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */
858: ARG(1, T_PATH);
859: int as = 0;
860: as_path_get_last(v1.val.ad, &as);
861: RESULT(T_INT, i, as);
862: }
863:
864: INST(FI_AS_PATH_LAST_NAG, 1, 1) { /* Get last ASN from non-aggregated part of AS PATH */
865: ARG(1, T_PATH);
866: RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
867: }
868:
869: INST(FI_RETURN, 1, 1) {
870: NEVER_CONSTANT;
871: /* Acquire the return value */
872: ARG_ANY(1);
873: uint retpos = fstk->vcnt;
874:
875: /* Drop every sub-block including ourselves */
876: while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
877: ;
878:
879: /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
880: if (!fstk->ecnt)
881: if (fstk->vstk[retpos].type == T_BOOL)
882: if (fstk->vstk[retpos].val.i)
883: return F_ACCEPT;
884: else
885: return F_REJECT;
886: else
887: runtime("Can't return non-bool from non-function");
888:
889: /* Set the value stack position, overwriting the former implicit void */
890: fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
891:
892: /* Copy the return value */
893: RESULT_VAL(fstk->vstk[retpos]);
894: }
895:
896: INST(FI_CALL, 0, 1) {
897: NEVER_CONSTANT;
898: SYMBOL;
899:
900: FID_SAME_BODY()
901: if (!(f2->sym->flags & SYM_FLAG_SAME))
902: return 0;
903: FID_INTERPRET_BODY()
904:
905: /* Push the body on stack */
906: LINEX(sym->function);
907: curline.emask |= FE_RETURN;
908:
909: /* Before this instruction was called, there was the T_VOID
910: * automatic return value pushed on value stack and also
911: * sym->function->args function arguments. Setting the
912: * vbase to point to first argument. */
913: ASSERT(curline.ventry >= sym->function->args);
914: curline.ventry -= sym->function->args;
915: curline.vbase = curline.ventry;
916:
917: /* Storage for local variables */
918: memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
919: fstk->vcnt += sym->function->vars;
920: }
921:
922: INST(FI_DROP_RESULT, 1, 0) {
923: NEVER_CONSTANT;
924: ARG_ANY(1);
925: }
926:
927: INST(FI_SWITCH, 1, 0) {
928: ARG_ANY(1);
929:
930: FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
931:
932: const struct f_tree *t = find_tree(tree, &v1);
933: if (!t) {
934: v1.type = T_VOID;
935: t = find_tree(tree, &v1);
936: if (!t) {
937: debug( "No else statement?\n");
938: FID_HIC(,break,return NULL);
939: }
940: }
941: /* It is actually possible to have t->data NULL */
942:
943: LINEX(t->data);
944: }
945:
946: INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */
947: ARG(1, T_IP);
948: ARG(2, T_INT);
949: RESULT(T_IP, ip, [[ ipa_is_ip4(v1.val.ip) ?
950: ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
951: ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]);
952: }
953:
954: INST(FI_PATH_PREPEND, 2, 1) { /* Path prepend */
955: ARG(1, T_PATH);
956: ARG(2, T_INT);
957: RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]);
958: }
959:
960: INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */
961: ARG_ANY(1);
962: ARG_ANY(2);
963: if (v1.type == T_PATH)
964: runtime("Can't add to path");
965:
966: else if (v1.type == T_CLIST)
967: {
968: /* Community (or cluster) list */
969: struct f_val dummy;
970:
971: if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
972: RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
973: /* IP->Quad implicit conversion */
974: else if (val_is_ip4(&v2))
975: RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
976: else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
977: runtime("Can't add set");
978: else if (v2.type == T_CLIST)
979: RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
980: else
981: runtime("Can't add non-pair");
982: }
983:
984: else if (v1.type == T_ECLIST)
985: {
986: /* v2.val is either EC or EC-set */
987: if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
988: runtime("Can't add set");
989: else if (v2.type == T_ECLIST)
990: RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
991: else if (v2.type != T_EC)
992: runtime("Can't add non-ec");
993: else
994: RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
995: }
996:
997: else if (v1.type == T_LCLIST)
998: {
999: /* v2.val is either LC or LC-set */
1000: if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
1001: runtime("Can't add set");
1002: else if (v2.type == T_LCLIST)
1003: RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
1004: else if (v2.type != T_LC)
1005: runtime("Can't add non-lc");
1006: else
1007: RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
1008:
1009: }
1010:
1011: else
1012: runtime("Can't add to non-[e|l]clist");
1013: }
1014:
1015: INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
1016: ARG_ANY(1);
1017: ARG_ANY(2);
1018: if (v1.type == T_PATH)
1019: {
1020: const struct f_tree *set = NULL;
1021: u32 key = 0;
1022:
1023: if (v2.type == T_INT)
1024: key = v2.val.i;
1025: else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
1026: set = v2.val.t;
1027: else
1028: runtime("Can't delete non-integer (set)");
1029:
1030: RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
1031: }
1032:
1033: else if (v1.type == T_CLIST)
1034: {
1035: /* Community (or cluster) list */
1036: struct f_val dummy;
1037:
1038: if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
1039: RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
1040: /* IP->Quad implicit conversion */
1041: else if (val_is_ip4(&v2))
1042: RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
1043: else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
1044: RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
1045: else
1046: runtime("Can't delete non-pair");
1047: }
1048:
1049: else if (v1.type == T_ECLIST)
1050: {
1051: /* v2.val is either EC or EC-set */
1052: if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
1053: RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
1054: else if (v2.type != T_EC)
1055: runtime("Can't delete non-ec");
1056: else
1057: RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
1058: }
1059:
1060: else if (v1.type == T_LCLIST)
1061: {
1062: /* v2.val is either LC or LC-set */
1063: if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
1064: RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
1065: else if (v2.type != T_LC)
1066: runtime("Can't delete non-lc");
1067: else
1068: RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
1069: }
1070:
1071: else
1072: runtime("Can't delete in non-[e|l]clist");
1073: }
1074:
1075: INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */
1076: ARG_ANY(1);
1077: ARG_ANY(2);
1078: if (v1.type == T_PATH)
1079: {
1080: u32 key = 0;
1081:
1082: if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
1083: RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
1084: else
1085: runtime("Can't filter integer");
1086: }
1087:
1088: else if (v1.type == T_CLIST)
1089: {
1090: /* Community (or cluster) list */
1091: struct f_val dummy;
1092:
1093: if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
1094: RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
1095: else
1096: runtime("Can't filter pair");
1097: }
1098:
1099: else if (v1.type == T_ECLIST)
1100: {
1101: /* v2.val is either EC or EC-set */
1102: if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
1103: RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
1104: else
1105: runtime("Can't filter ec");
1106: }
1107:
1108: else if (v1.type == T_LCLIST)
1109: {
1110: /* v2.val is either LC or LC-set */
1111: if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
1112: RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
1113: else
1114: runtime("Can't filter lc");
1115: }
1116:
1117: else
1118: runtime("Can't filter non-[e|l]clist");
1119: }
1120:
1121: INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */
1122: NEVER_CONSTANT;
1123: RTC(1);
1124: struct rtable *table = rtc->table;
1125: ACCESS_RTE;
1126: ACCESS_EATTRS;
1127: const net_addr *net = (*fs->rte)->net->n.addr;
1128:
1129: /* We ignore temporary attributes, probably not a problem here */
1130: /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
1131: eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
1132:
1133: if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
1134: runtime("Missing AS_PATH attribute");
1135:
1136: u32 as = 0;
1137: as_path_get_last(e->u.ptr, &as);
1138:
1139: if (!table)
1140: runtime("Missing ROA table");
1141:
1142: if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
1143: runtime("Table type must be either ROA4 or ROA6");
1144:
1145: if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
1146: RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
1147: else
1148: RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]);
1149: }
1150:
1151: INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */
1152: NEVER_CONSTANT;
1153: ARG(1, T_NET);
1154: ARG(2, T_INT);
1155: RTC(3);
1156: struct rtable *table = rtc->table;
1157:
1158: u32 as = v2.val.i;
1159:
1160: if (!table)
1161: runtime("Missing ROA table");
1162:
1163: if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
1164: runtime("Table type must be either ROA4 or ROA6");
1165:
1166: if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
1167: RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
1168: else
1169: RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, v1.val.net, as) ]]);
1170:
1171: }
1172:
1173: INST(FI_FORMAT, 1, 0) { /* Format */
1174: ARG_ANY(1);
1175: RESULT(T_STRING, s, val_format_str(fpool, &v1));
1176: }
1177:
1178: INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
1179: NEVER_CONSTANT;
1180: ARG(1, T_BOOL);
1181:
1182: FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], "string %s", item->s);
1183:
1184: ASSERT(s);
1185:
1186: if (!bt_assert_hook)
1187: runtime("No bt_assert hook registered, can't assert");
1188:
1189: bt_assert_hook(v1.val.i, what);
1190: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>