]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/data.c
Add compile-time option to enable 4-way tries instead of 16-way ones
[thirdparty/bird.git] / filter / data.c
CommitLineData
52893045
MM
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
87512e97
OZ
28static const char * const f_type_str[] = {
29 [T_VOID] = "void",
30
31 [T_INT] = "int",
32 [T_BOOL] = "bool",
33 [T_PAIR] = "pair",
34 [T_QUAD] = "quad",
35
36 [T_ENUM_RTS] = "enum rts",
37 [T_ENUM_BGP_ORIGIN] = "enum bgp_origin",
38 [T_ENUM_SCOPE] = "enum scope",
39 [T_ENUM_RTC] = "enum rtc",
40 [T_ENUM_RTD] = "enum rtd",
41 [T_ENUM_ROA] = "enum roa",
42 [T_ENUM_NETTYPE] = "enum nettype",
43 [T_ENUM_RA_PREFERENCE] = "enum ra_preference",
44 [T_ENUM_AF] = "enum af",
45
46 [T_IP] = "ip",
47 [T_NET] = "prefix",
48 [T_STRING] = "string",
49 [T_PATH_MASK] = "bgpmask",
50 [T_PATH] = "bgppath",
51 [T_CLIST] = "clist",
52 [T_EC] = "ec",
53 [T_ECLIST] = "eclist",
54 [T_LC] = "lc",
55 [T_LCLIST] = "lclist",
56 [T_RD] = "rd",
57};
58
59const char *
60f_type_name(enum f_type t)
61{
62 if (t < ARRAY_SIZE(f_type_str))
63 return f_type_str[t] ?: "?";
64
65 if ((t == T_SET) || (t == T_PREFIX_SET))
66 return "set";
67
68 return "?";
69}
70
0e1fd7ea
AZ
71enum f_type
72f_type_element_type(enum f_type t)
73{
74 switch(t) {
cb339a30 75 case T_PATH: return T_INT;
0e1fd7ea
AZ
76 case T_CLIST: return T_PAIR;
77 case T_ECLIST: return T_EC;
78 case T_LCLIST: return T_LC;
79 default: return T_VOID;
80 };
81}
82
b2d6d294
AZ
83const struct f_trie f_const_empty_trie = { .ipv4 = -1, };
84
52893045
MM
85const struct f_val f_const_empty_path = {
86 .type = T_PATH,
87 .val.ad = &null_adata,
88}, f_const_empty_clist = {
89 .type = T_CLIST,
90 .val.ad = &null_adata,
91}, f_const_empty_eclist = {
92 .type = T_ECLIST,
93 .val.ad = &null_adata,
94}, f_const_empty_lclist = {
95 .type = T_LCLIST,
96 .val.ad = &null_adata,
b2d6d294
AZ
97}, f_const_empty_prefix_set = {
98 .type = T_PREFIX_SET,
99 .val.ti = &f_const_empty_trie,
52893045
MM
100};
101
102static struct adata *
103adata_empty(struct linpool *pool, int l)
104{
105 struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
106 res->length = l;
107 return res;
108}
109
110static void
111pm_format(const struct f_path_mask *p, buffer *buf)
112{
ec430a7f
OZ
113 int loop = 0;
114
52893045
MM
115 buffer_puts(buf, "[= ");
116
117 for (uint i=0; i<p->len; i++)
118 {
119 switch(p->item[i].kind)
120 {
121 case PM_ASN:
122 buffer_print(buf, "%u ", p->item[i].asn);
123 break;
124
125 case PM_QUESTION:
126 buffer_puts(buf, "? ");
127 break;
128
129 case PM_ASTERISK:
130 buffer_puts(buf, "* ");
131 break;
132
ec430a7f
OZ
133 case PM_LOOP:
134 loop = 1;
135 break;
136
52893045
MM
137 case PM_ASN_RANGE:
138 buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
139 break;
140
a948cf9a
KY
141 case PM_ASN_SET:
142 tree_format(p->item[i].set, buf);
143 buffer_puts(buf, " ");
144 break;
145
52893045
MM
146 case PM_ASN_EXPR:
147 ASSERT(0);
148 }
149
ec430a7f
OZ
150 if (loop && (p->item[i].kind != PM_LOOP))
151 {
152 buffer_puts(buf, "+ ");
153 loop = 0;
154 }
52893045
MM
155 }
156
157 buffer_puts(buf, "=]");
158}
159
160static inline int
161lcomm_cmp(lcomm v1, lcomm v2)
162{
163 if (v1.asn != v2.asn)
164 return (v1.asn > v2.asn) ? 1 : -1;
165 if (v1.ldp1 != v2.ldp1)
166 return (v1.ldp1 > v2.ldp1) ? 1 : -1;
167 if (v1.ldp2 != v2.ldp2)
168 return (v1.ldp2 > v2.ldp2) ? 1 : -1;
169 return 0;
170}
171
172/**
173 * val_compare - compare two values
174 * @v1: first value
175 * @v2: second value
176 *
177 * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on
178 * error. Tree module relies on this giving consistent results so
179 * that it can be used for building balanced trees.
180 */
181int
182val_compare(const struct f_val *v1, const struct f_val *v2)
183{
184 if (v1->type != v2->type) {
185 if (v1->type == T_VOID) /* Hack for else */
186 return -1;
187 if (v2->type == T_VOID)
188 return 1;
189
190 /* IP->Quad implicit conversion */
191 if ((v1->type == T_QUAD) && val_is_ip4(v2))
192 return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
193 if (val_is_ip4(v1) && (v2->type == T_QUAD))
194 return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
195
fb1d8f65 196 DBG( "Types do not match in val_compare\n" );
52893045
MM
197 return F_CMP_ERROR;
198 }
199
200 switch (v1->type) {
201 case T_VOID:
202 return 0;
203 case T_ENUM:
204 case T_INT:
205 case T_BOOL:
206 case T_PAIR:
207 case T_QUAD:
208 return uint_cmp(v1->val.i, v2->val.i);
209 case T_EC:
210 case T_RD:
211 return u64_cmp(v1->val.ec, v2->val.ec);
212 case T_LC:
213 return lcomm_cmp(v1->val.lc, v2->val.lc);
214 case T_IP:
215 return ipa_compare(v1->val.ip, v2->val.ip);
216 case T_NET:
217 return net_compare(v1->val.net, v2->val.net);
218 case T_STRING:
219 return strcmp(v1->val.s, v2->val.s);
220 default:
221 return F_CMP_ERROR;
222 }
223}
224
132529ce
MM
225static inline int
226pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2)
227{
228 if (mi1->kind != mi2->kind)
229 return 0;
230
231 switch (mi1->kind) {
232 case PM_ASN:
233 if (mi1->asn != mi2->asn)
234 return 0;
235 break;
236 case PM_ASN_EXPR:
237 if (!f_same(mi1->expr, mi2->expr))
238 return 0;
239 break;
240 case PM_ASN_RANGE:
241 if (mi1->from != mi2->from)
242 return 0;
243 if (mi1->to != mi2->to)
244 return 0;
245 break;
a948cf9a
KY
246 case PM_ASN_SET:
247 if (!same_tree(mi1->set, mi2->set))
248 return 0;
249 break;
132529ce
MM
250 }
251
252 return 1;
253}
254
52893045
MM
255static int
256pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
257{
258 if (m1->len != m2->len)
4ef0a966 259 return 0;
52893045
MM
260
261 for (uint i=0; i<m1->len; i++)
132529ce 262 if (!pmi_same(&(m1->item[i]), &(m2->item[i])))
52893045
MM
263 return 0;
264
52893045
MM
265 return 1;
266}
267
268/**
269 * val_same - compare two values
270 * @v1: first value
271 * @v2: second value
272 *
273 * Compares two values and returns 1 if they are same and 0 if not.
274 * Comparison of values of different types is valid and returns 0.
275 */
276int
277val_same(const struct f_val *v1, const struct f_val *v2)
278{
279 int rc;
280
281 rc = val_compare(v1, v2);
282 if (rc != F_CMP_ERROR)
283 return !rc;
284
285 if (v1->type != v2->type)
286 return 0;
287
288 switch (v1->type) {
289 case T_PATH_MASK:
290 return pm_same(v1->val.path_mask, v2->val.path_mask);
132529ce
MM
291 case T_PATH_MASK_ITEM:
292 return pmi_same(&(v1->val.pmi), &(v2->val.pmi));
52893045
MM
293 case T_PATH:
294 case T_CLIST:
295 case T_ECLIST:
296 case T_LCLIST:
297 return adata_same(v1->val.ad, v2->val.ad);
298 case T_SET:
299 return same_tree(v1->val.t, v2->val.t);
300 case T_PREFIX_SET:
301 return trie_same(v1->val.ti, v2->val.ti);
302 default:
303 bug("Invalid type in val_same(): %x", v1->type);
304 }
305}
306
307int
308clist_set_type(const struct f_tree *set, struct f_val *v)
309{
b2d6d294
AZ
310 if (!set)
311 {
312 v->type = T_VOID;
313 return 1;
314 }
315
52893045
MM
316 switch (set->from.type)
317 {
318 case T_PAIR:
319 v->type = T_PAIR;
320 return 1;
321
322 case T_QUAD:
323 v->type = T_QUAD;
324 return 1;
325
326 case T_IP:
327 if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
328 {
329 v->type = T_QUAD;
330 return 1;
331 }
332 /* Fall through */
333 default:
334 v->type = T_VOID;
335 return 0;
336 }
337}
338
92a85655 339int
52893045
MM
340clist_match_set(const struct adata *clist, const struct f_tree *set)
341{
342 if (!clist)
343 return 0;
344
345 struct f_val v;
346 if (!clist_set_type(set, &v))
347 return F_CMP_ERROR;
348
349 u32 *l = (u32 *) clist->data;
350 u32 *end = l + clist->length/4;
351
352 while (l < end) {
353 v.val.i = *l++;
354 if (find_tree(set, &v))
355 return 1;
356 }
357 return 0;
358}
359
92a85655 360int
52893045
MM
361eclist_match_set(const struct adata *list, const struct f_tree *set)
362{
363 if (!list)
364 return 0;
365
366 if (!eclist_set_type(set))
367 return F_CMP_ERROR;
368
369 struct f_val v;
370 u32 *l = int_set_get_data(list);
371 int len = int_set_get_size(list);
372 int i;
373
374 v.type = T_EC;
375 for (i = 0; i < len; i += 2) {
376 v.val.ec = ec_get(l, i);
377 if (find_tree(set, &v))
378 return 1;
379 }
380
381 return 0;
382}
383
92a85655 384int
52893045
MM
385lclist_match_set(const struct adata *list, const struct f_tree *set)
386{
387 if (!list)
388 return 0;
389
390 if (!lclist_set_type(set))
391 return F_CMP_ERROR;
392
393 struct f_val v;
394 u32 *l = int_set_get_data(list);
395 int len = int_set_get_size(list);
396 int i;
397
398 v.type = T_LC;
399 for (i = 0; i < len; i += 3) {
400 v.val.lc = lc_get(l, i);
401 if (find_tree(set, &v))
402 return 1;
403 }
404
405 return 0;
406}
407
408const struct adata *
409clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
410{
411 if (!list)
412 return NULL;
413
414 int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
415 struct f_val v;
416 if (tree)
417 clist_set_type(set->val.t, &v);
418 else
419 v.type = T_PAIR;
420
421 int len = int_set_get_size(list);
422 u32 *l = int_set_get_data(list);
423 u32 tmp[len];
424 u32 *k = tmp;
425 u32 *end = l + len;
426
427 while (l < end) {
428 v.val.i = *l++;
429 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
430 if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
431 *k++ = v.val.i;
432 }
433
434 uint nl = (k - tmp) * sizeof(u32);
435 if (nl == list->length)
436 return list;
437
438 struct adata *res = adata_empty(pool, nl);
439 memcpy(res->data, tmp, nl);
440 return res;
441}
442
443const struct adata *
444eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
445{
446 if (!list)
447 return NULL;
448
449 int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
450 struct f_val v;
451
452 int len = int_set_get_size(list);
453 u32 *l = int_set_get_data(list);
454 u32 tmp[len];
455 u32 *k = tmp;
456 int i;
457
458 v.type = T_EC;
459 for (i = 0; i < len; i += 2) {
460 v.val.ec = ec_get(l, i);
461 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
462 if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
463 *k++ = l[i];
464 *k++ = l[i+1];
465 }
466 }
467
468 uint nl = (k - tmp) * sizeof(u32);
469 if (nl == list->length)
470 return list;
471
472 struct adata *res = adata_empty(pool, nl);
473 memcpy(res->data, tmp, nl);
474 return res;
475}
476
477const struct adata *
478lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
479{
480 if (!list)
481 return NULL;
482
483 int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
484 struct f_val v;
485
486 int len = int_set_get_size(list);
487 u32 *l = int_set_get_data(list);
488 u32 tmp[len];
489 u32 *k = tmp;
490 int i;
491
492 v.type = T_LC;
493 for (i = 0; i < len; i += 3) {
494 v.val.lc = lc_get(l, i);
495 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
496 if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
497 k = lc_copy(k, l+i);
498 }
499
500 uint nl = (k - tmp) * sizeof(u32);
501 if (nl == list->length)
502 return list;
503
504 struct adata *res = adata_empty(pool, nl);
505 memcpy(res->data, tmp, nl);
506 return res;
507}
508
509/**
510 * val_in_range - implement |~| operator
511 * @v1: element
512 * @v2: set
513 *
514 * Checks if @v1 is element (|~| operator) of @v2.
515 */
516int
517val_in_range(const struct f_val *v1, const struct f_val *v2)
518{
519 if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
520 return as_path_match(v1->val.ad, v2->val.path_mask);
521
522 if ((v1->type == T_INT) && (v2->type == T_PATH))
523 return as_path_contains(v2->val.ad, v1->val.i, 1);
524
525 if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
526 return int_set_contains(v2->val.ad, v1->val.i);
527 /* IP->Quad implicit conversion */
528 if (val_is_ip4(v1) && (v2->type == T_CLIST))
529 return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
530
531 if ((v1->type == T_EC) && (v2->type == T_ECLIST))
532 return ec_set_contains(v2->val.ad, v1->val.ec);
533
534 if ((v1->type == T_LC) && (v2->type == T_LCLIST))
535 return lc_set_contains(v2->val.ad, v1->val.lc);
536
537 if ((v1->type == T_STRING) && (v2->type == T_STRING))
538 return patmatch(v2->val.s, v1->val.s);
539
540 if ((v1->type == T_IP) && (v2->type == T_NET))
541 return ipa_in_netX(v1->val.ip, v2->val.net);
542
543 if ((v1->type == T_NET) && (v2->type == T_NET))
544 return net_in_netX(v1->val.net, v2->val.net);
545
546 if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
547 return trie_match_net(v2->val.ti, v1->val.net);
548
549 if (v2->type != T_SET)
550 return F_CMP_ERROR;
551
b2d6d294
AZ
552 if (!v2->val.t)
553 return 0;
554
52893045
MM
555 /* With integrated Quad<->IP implicit conversion */
556 if ((v1->type == v2->val.t->from.type) ||
557 ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
558 return !!find_tree(v2->val.t, v1);
559
560 if (v1->type == T_CLIST)
561 return clist_match_set(v1->val.ad, v2->val.t);
562
563 if (v1->type == T_ECLIST)
564 return eclist_match_set(v1->val.ad, v2->val.t);
565
566 if (v1->type == T_LCLIST)
567 return lclist_match_set(v1->val.ad, v2->val.t);
568
569 if (v1->type == T_PATH)
570 return as_path_match_set(v1->val.ad, v2->val.t);
571
572 return F_CMP_ERROR;
573}
574
575/*
576 * val_format - format filter value
577 */
578void
579val_format(const struct f_val *v, buffer *buf)
580{
581 char buf2[1024];
582 switch (v->type)
583 {
584 case T_VOID: buffer_puts(buf, "(void)"); return;
585 case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
586 case T_INT: buffer_print(buf, "%u", v->val.i); return;
587 case T_STRING: buffer_print(buf, "%s", v->val.s); return;
588 case T_IP: buffer_print(buf, "%I", v->val.ip); return;
589 case T_NET: buffer_print(buf, "%N", v->val.net); return;
590 case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
591 case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
592 case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
593 case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
594 case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
595 case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
596 case T_SET: tree_format(v->val.t, buf); return;
597 case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
598 case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
599 case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
600 case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
601 case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
602 case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
603 default: buffer_print(buf, "[unknown type %x]", v->type); return;
604 }
605}
606
b40c0f02
MM
607char *
608val_format_str(struct linpool *lp, const struct f_val *v) {
609 buffer b;
610 LOG_BUFFER_INIT(b);
611 val_format(v, &b);
612 return lp_strdup(lp, b.start);
613}
614
615
52893045
MM
616static char val_dump_buffer[1024];
617const char *
618val_dump(const struct f_val *v) {
619 static buffer b = {
620 .start = val_dump_buffer,
621 .end = val_dump_buffer + 1024,
622 };
623 b.pos = b.start;
624 val_format(v, &b);
625 return val_dump_buffer;
626}
a84b8b6e 627