Annotation of embedaddon/bird2/filter/data.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Filters: utility functions
3: *
4: * (c) 1998 Pavel Machek <pavel@ucw.cz>
5: * (c) 2019 Maria Matejka <mq@jmq.cz>
6: *
7: * Can be freely distributed and used under the terms of the GNU GPL.
8: *
9: */
10:
11: #include "nest/bird.h"
12: #include "lib/lists.h"
13: #include "lib/resource.h"
14: #include "lib/socket.h"
15: #include "lib/string.h"
16: #include "lib/unaligned.h"
17: #include "lib/net.h"
18: #include "lib/ip.h"
19: #include "nest/route.h"
20: #include "nest/protocol.h"
21: #include "nest/iface.h"
22: #include "nest/attrs.h"
23: #include "conf/conf.h"
24: #include "filter/filter.h"
25: #include "filter/f-inst.h"
26: #include "filter/data.h"
27:
28: const struct f_val f_const_empty_path = {
29: .type = T_PATH,
30: .val.ad = &null_adata,
31: }, f_const_empty_clist = {
32: .type = T_CLIST,
33: .val.ad = &null_adata,
34: }, f_const_empty_eclist = {
35: .type = T_ECLIST,
36: .val.ad = &null_adata,
37: }, f_const_empty_lclist = {
38: .type = T_LCLIST,
39: .val.ad = &null_adata,
40: };
41:
42: static struct adata *
43: adata_empty(struct linpool *pool, int l)
44: {
45: struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
46: res->length = l;
47: return res;
48: }
49:
50: static void
51: pm_format(const struct f_path_mask *p, buffer *buf)
52: {
53: buffer_puts(buf, "[= ");
54:
55: for (uint i=0; i<p->len; i++)
56: {
57: switch(p->item[i].kind)
58: {
59: case PM_ASN:
60: buffer_print(buf, "%u ", p->item[i].asn);
61: break;
62:
63: case PM_QUESTION:
64: buffer_puts(buf, "? ");
65: break;
66:
67: case PM_ASTERISK:
68: buffer_puts(buf, "* ");
69: break;
70:
71: case PM_ASN_RANGE:
72: buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
73: break;
74:
75: case PM_ASN_EXPR:
76: ASSERT(0);
77: }
78:
79: }
80:
81: buffer_puts(buf, "=]");
82: }
83:
84: static inline int
85: lcomm_cmp(lcomm v1, lcomm v2)
86: {
87: if (v1.asn != v2.asn)
88: return (v1.asn > v2.asn) ? 1 : -1;
89: if (v1.ldp1 != v2.ldp1)
90: return (v1.ldp1 > v2.ldp1) ? 1 : -1;
91: if (v1.ldp2 != v2.ldp2)
92: return (v1.ldp2 > v2.ldp2) ? 1 : -1;
93: return 0;
94: }
95:
96: /**
97: * val_compare - compare two values
98: * @v1: first value
99: * @v2: second value
100: *
101: * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on
102: * error. Tree module relies on this giving consistent results so
103: * that it can be used for building balanced trees.
104: */
105: int
106: val_compare(const struct f_val *v1, const struct f_val *v2)
107: {
108: if (v1->type != v2->type) {
109: if (v1->type == T_VOID) /* Hack for else */
110: return -1;
111: if (v2->type == T_VOID)
112: return 1;
113:
114: /* IP->Quad implicit conversion */
115: if ((v1->type == T_QUAD) && val_is_ip4(v2))
116: return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
117: if (val_is_ip4(v1) && (v2->type == T_QUAD))
118: return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
119:
120: debug( "Types do not match in val_compare\n" );
121: return F_CMP_ERROR;
122: }
123:
124: switch (v1->type) {
125: case T_VOID:
126: return 0;
127: case T_ENUM:
128: case T_INT:
129: case T_BOOL:
130: case T_PAIR:
131: case T_QUAD:
132: return uint_cmp(v1->val.i, v2->val.i);
133: case T_EC:
134: case T_RD:
135: return u64_cmp(v1->val.ec, v2->val.ec);
136: case T_LC:
137: return lcomm_cmp(v1->val.lc, v2->val.lc);
138: case T_IP:
139: return ipa_compare(v1->val.ip, v2->val.ip);
140: case T_NET:
141: return net_compare(v1->val.net, v2->val.net);
142: case T_STRING:
143: return strcmp(v1->val.s, v2->val.s);
144: default:
145: return F_CMP_ERROR;
146: }
147: }
148:
149: static inline int
150: pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2)
151: {
152: if (mi1->kind != mi2->kind)
153: return 0;
154:
155: switch (mi1->kind) {
156: case PM_ASN:
157: if (mi1->asn != mi2->asn)
158: return 0;
159: break;
160: case PM_ASN_EXPR:
161: if (!f_same(mi1->expr, mi2->expr))
162: return 0;
163: break;
164: case PM_ASN_RANGE:
165: if (mi1->from != mi2->from)
166: return 0;
167: if (mi1->to != mi2->to)
168: return 0;
169: break;
170: }
171:
172: return 1;
173: }
174:
175: static int
176: pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
177: {
178: if (m1->len != m2->len)
179:
180: for (uint i=0; i<m1->len; i++)
181: if (!pmi_same(&(m1->item[i]), &(m2->item[i])))
182: return 0;
183:
184: return 1;
185: }
186:
187: /**
188: * val_same - compare two values
189: * @v1: first value
190: * @v2: second value
191: *
192: * Compares two values and returns 1 if they are same and 0 if not.
193: * Comparison of values of different types is valid and returns 0.
194: */
195: int
196: val_same(const struct f_val *v1, const struct f_val *v2)
197: {
198: int rc;
199:
200: rc = val_compare(v1, v2);
201: if (rc != F_CMP_ERROR)
202: return !rc;
203:
204: if (v1->type != v2->type)
205: return 0;
206:
207: switch (v1->type) {
208: case T_PATH_MASK:
209: return pm_same(v1->val.path_mask, v2->val.path_mask);
210: case T_PATH_MASK_ITEM:
211: return pmi_same(&(v1->val.pmi), &(v2->val.pmi));
212: case T_PATH:
213: case T_CLIST:
214: case T_ECLIST:
215: case T_LCLIST:
216: return adata_same(v1->val.ad, v2->val.ad);
217: case T_SET:
218: return same_tree(v1->val.t, v2->val.t);
219: case T_PREFIX_SET:
220: return trie_same(v1->val.ti, v2->val.ti);
221: default:
222: bug("Invalid type in val_same(): %x", v1->type);
223: }
224: }
225:
226: int
227: clist_set_type(const struct f_tree *set, struct f_val *v)
228: {
229: switch (set->from.type)
230: {
231: case T_PAIR:
232: v->type = T_PAIR;
233: return 1;
234:
235: case T_QUAD:
236: v->type = T_QUAD;
237: return 1;
238:
239: case T_IP:
240: if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
241: {
242: v->type = T_QUAD;
243: return 1;
244: }
245: /* Fall through */
246: default:
247: v->type = T_VOID;
248: return 0;
249: }
250: }
251:
252: static int
253: clist_match_set(const struct adata *clist, const struct f_tree *set)
254: {
255: if (!clist)
256: return 0;
257:
258: struct f_val v;
259: if (!clist_set_type(set, &v))
260: return F_CMP_ERROR;
261:
262: u32 *l = (u32 *) clist->data;
263: u32 *end = l + clist->length/4;
264:
265: while (l < end) {
266: v.val.i = *l++;
267: if (find_tree(set, &v))
268: return 1;
269: }
270: return 0;
271: }
272:
273: static int
274: eclist_match_set(const struct adata *list, const struct f_tree *set)
275: {
276: if (!list)
277: return 0;
278:
279: if (!eclist_set_type(set))
280: return F_CMP_ERROR;
281:
282: struct f_val v;
283: u32 *l = int_set_get_data(list);
284: int len = int_set_get_size(list);
285: int i;
286:
287: v.type = T_EC;
288: for (i = 0; i < len; i += 2) {
289: v.val.ec = ec_get(l, i);
290: if (find_tree(set, &v))
291: return 1;
292: }
293:
294: return 0;
295: }
296:
297: static int
298: lclist_match_set(const struct adata *list, const struct f_tree *set)
299: {
300: if (!list)
301: return 0;
302:
303: if (!lclist_set_type(set))
304: return F_CMP_ERROR;
305:
306: struct f_val v;
307: u32 *l = int_set_get_data(list);
308: int len = int_set_get_size(list);
309: int i;
310:
311: v.type = T_LC;
312: for (i = 0; i < len; i += 3) {
313: v.val.lc = lc_get(l, i);
314: if (find_tree(set, &v))
315: return 1;
316: }
317:
318: return 0;
319: }
320:
321: const struct adata *
322: clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
323: {
324: if (!list)
325: return NULL;
326:
327: int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
328: struct f_val v;
329: if (tree)
330: clist_set_type(set->val.t, &v);
331: else
332: v.type = T_PAIR;
333:
334: int len = int_set_get_size(list);
335: u32 *l = int_set_get_data(list);
336: u32 tmp[len];
337: u32 *k = tmp;
338: u32 *end = l + len;
339:
340: while (l < end) {
341: v.val.i = *l++;
342: /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
343: if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
344: *k++ = v.val.i;
345: }
346:
347: uint nl = (k - tmp) * sizeof(u32);
348: if (nl == list->length)
349: return list;
350:
351: struct adata *res = adata_empty(pool, nl);
352: memcpy(res->data, tmp, nl);
353: return res;
354: }
355:
356: const struct adata *
357: eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
358: {
359: if (!list)
360: return NULL;
361:
362: int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
363: struct f_val v;
364:
365: int len = int_set_get_size(list);
366: u32 *l = int_set_get_data(list);
367: u32 tmp[len];
368: u32 *k = tmp;
369: int i;
370:
371: v.type = T_EC;
372: for (i = 0; i < len; i += 2) {
373: v.val.ec = ec_get(l, i);
374: /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
375: if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
376: *k++ = l[i];
377: *k++ = l[i+1];
378: }
379: }
380:
381: uint nl = (k - tmp) * sizeof(u32);
382: if (nl == list->length)
383: return list;
384:
385: struct adata *res = adata_empty(pool, nl);
386: memcpy(res->data, tmp, nl);
387: return res;
388: }
389:
390: const struct adata *
391: lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
392: {
393: if (!list)
394: return NULL;
395:
396: int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
397: struct f_val v;
398:
399: int len = int_set_get_size(list);
400: u32 *l = int_set_get_data(list);
401: u32 tmp[len];
402: u32 *k = tmp;
403: int i;
404:
405: v.type = T_LC;
406: for (i = 0; i < len; i += 3) {
407: v.val.lc = lc_get(l, i);
408: /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
409: if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
410: k = lc_copy(k, l+i);
411: }
412:
413: uint nl = (k - tmp) * sizeof(u32);
414: if (nl == list->length)
415: return list;
416:
417: struct adata *res = adata_empty(pool, nl);
418: memcpy(res->data, tmp, nl);
419: return res;
420: }
421:
422: /**
423: * val_in_range - implement |~| operator
424: * @v1: element
425: * @v2: set
426: *
427: * Checks if @v1 is element (|~| operator) of @v2.
428: */
429: int
430: val_in_range(const struct f_val *v1, const struct f_val *v2)
431: {
432: if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
433: return as_path_match(v1->val.ad, v2->val.path_mask);
434:
435: if ((v1->type == T_INT) && (v2->type == T_PATH))
436: return as_path_contains(v2->val.ad, v1->val.i, 1);
437:
438: if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
439: return int_set_contains(v2->val.ad, v1->val.i);
440: /* IP->Quad implicit conversion */
441: if (val_is_ip4(v1) && (v2->type == T_CLIST))
442: return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
443:
444: if ((v1->type == T_EC) && (v2->type == T_ECLIST))
445: return ec_set_contains(v2->val.ad, v1->val.ec);
446:
447: if ((v1->type == T_LC) && (v2->type == T_LCLIST))
448: return lc_set_contains(v2->val.ad, v1->val.lc);
449:
450: if ((v1->type == T_STRING) && (v2->type == T_STRING))
451: return patmatch(v2->val.s, v1->val.s);
452:
453: if ((v1->type == T_IP) && (v2->type == T_NET))
454: return ipa_in_netX(v1->val.ip, v2->val.net);
455:
456: if ((v1->type == T_NET) && (v2->type == T_NET))
457: return net_in_netX(v1->val.net, v2->val.net);
458:
459: if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
460: return trie_match_net(v2->val.ti, v1->val.net);
461:
462: if (v2->type != T_SET)
463: return F_CMP_ERROR;
464:
465: /* With integrated Quad<->IP implicit conversion */
466: if ((v1->type == v2->val.t->from.type) ||
467: ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
468: return !!find_tree(v2->val.t, v1);
469:
470: if (v1->type == T_CLIST)
471: return clist_match_set(v1->val.ad, v2->val.t);
472:
473: if (v1->type == T_ECLIST)
474: return eclist_match_set(v1->val.ad, v2->val.t);
475:
476: if (v1->type == T_LCLIST)
477: return lclist_match_set(v1->val.ad, v2->val.t);
478:
479: if (v1->type == T_PATH)
480: return as_path_match_set(v1->val.ad, v2->val.t);
481:
482: return F_CMP_ERROR;
483: }
484:
485: /*
486: * val_format - format filter value
487: */
488: void
489: val_format(const struct f_val *v, buffer *buf)
490: {
491: char buf2[1024];
492: switch (v->type)
493: {
494: case T_VOID: buffer_puts(buf, "(void)"); return;
495: case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
496: case T_INT: buffer_print(buf, "%u", v->val.i); return;
497: case T_STRING: buffer_print(buf, "%s", v->val.s); return;
498: case T_IP: buffer_print(buf, "%I", v->val.ip); return;
499: case T_NET: buffer_print(buf, "%N", v->val.net); return;
500: case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
501: case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
502: case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
503: case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
504: case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
505: case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
506: case T_SET: tree_format(v->val.t, buf); return;
507: case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
508: case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
509: case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
510: case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
511: case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
512: case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
513: default: buffer_print(buf, "[unknown type %x]", v->type); return;
514: }
515: }
516:
517: char *
518: val_format_str(struct linpool *lp, const struct f_val *v) {
519: buffer b;
520: LOG_BUFFER_INIT(b);
521: val_format(v, &b);
522: return lp_strdup(lp, b.start);
523: }
524:
525:
526: static char val_dump_buffer[1024];
527: const char *
528: val_dump(const struct f_val *v) {
529: static buffer b = {
530: .start = val_dump_buffer,
531: .end = val_dump_buffer + 1024,
532: };
533: b.pos = b.start;
534: val_format(v, &b);
535: return val_dump_buffer;
536: }
537:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>