]>
git.ipfire.org Git - thirdparty/bird.git/blob - filter/data.c
2 * Filters: utility functions
4 * (c) 1998 Pavel Machek <pavel@ucw.cz>
5 * (c) 2019 Maria Matejka <mq@jmq.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
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"
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"
28 const struct f_val f_const_empty_path
= {
30 .val
.ad
= &null_adata
,
31 }, f_const_empty_clist
= {
33 .val
.ad
= &null_adata
,
34 }, f_const_empty_eclist
= {
36 .val
.ad
= &null_adata
,
37 }, f_const_empty_lclist
= {
39 .val
.ad
= &null_adata
,
43 adata_empty(struct linpool
*pool
, int l
)
45 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
) + l
);
51 pm_format(const struct f_path_mask
*p
, buffer
*buf
)
53 buffer_puts(buf
, "[= ");
55 for (uint i
=0; i
<p
->len
; i
++)
57 switch(p
->item
[i
].kind
)
60 buffer_print(buf
, "%u ", p
->item
[i
].asn
);
64 buffer_puts(buf
, "? ");
68 buffer_puts(buf
, "* ");
72 buffer_print(buf
, "%u..%u ", p
->item
[i
].from
, p
->item
[i
].to
);
81 buffer_puts(buf
, "=]");
85 lcomm_cmp(lcomm v1
, lcomm v2
)
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;
97 * val_compare - compare two values
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.
106 val_compare(const struct f_val
*v1
, const struct f_val
*v2
)
108 if (v1
->type
!= v2
->type
) {
109 if (v1
->type
== T_VOID
) /* Hack for else */
111 if (v2
->type
== T_VOID
)
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
);
120 debug( "Types do not match in val_compare\n" );
132 return uint_cmp(v1
->val
.i
, v2
->val
.i
);
135 return u64_cmp(v1
->val
.ec
, v2
->val
.ec
);
137 return lcomm_cmp(v1
->val
.lc
, v2
->val
.lc
);
139 return ipa_compare(v1
->val
.ip
, v2
->val
.ip
);
141 return net_compare(v1
->val
.net
, v2
->val
.net
);
143 return strcmp(v1
->val
.s
, v2
->val
.s
);
150 pm_same(const struct f_path_mask
*m1
, const struct f_path_mask
*m2
)
152 if (m1
->len
!= m2
->len
)
154 for (uint i
=0; i
<m1
->len
; i
++)
156 if (m1
->item
[i
].kind
!= m2
->item
[i
].kind
)
159 switch (m1
->item
[i
].kind
) {
161 if (m1
->item
[i
].asn
!= m2
->item
[i
].asn
)
165 if (!f_same(m1
->item
[i
].expr
, m2
->item
[i
].expr
))
169 if (m1
->item
[i
].from
!= m2
->item
[i
].from
)
171 if (m1
->item
[i
].to
!= m2
->item
[i
].to
)
181 * val_same - compare two values
185 * Compares two values and returns 1 if they are same and 0 if not.
186 * Comparison of values of different types is valid and returns 0.
189 val_same(const struct f_val
*v1
, const struct f_val
*v2
)
193 rc
= val_compare(v1
, v2
);
194 if (rc
!= F_CMP_ERROR
)
197 if (v1
->type
!= v2
->type
)
202 return pm_same(v1
->val
.path_mask
, v2
->val
.path_mask
);
207 return adata_same(v1
->val
.ad
, v2
->val
.ad
);
209 return same_tree(v1
->val
.t
, v2
->val
.t
);
211 return trie_same(v1
->val
.ti
, v2
->val
.ti
);
213 bug("Invalid type in val_same(): %x", v1
->type
);
218 clist_set_type(const struct f_tree
*set
, struct f_val
*v
)
220 switch (set
->from
.type
)
231 if (val_is_ip4(&(set
->from
)) && val_is_ip4(&(set
->to
)))
244 clist_match_set(const struct adata
*clist
, const struct f_tree
*set
)
250 if (!clist_set_type(set
, &v
))
253 u32
*l
= (u32
*) clist
->data
;
254 u32
*end
= l
+ clist
->length
/4;
258 if (find_tree(set
, &v
))
265 eclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
270 if (!eclist_set_type(set
))
274 u32
*l
= int_set_get_data(list
);
275 int len
= int_set_get_size(list
);
279 for (i
= 0; i
< len
; i
+= 2) {
280 v
.val
.ec
= ec_get(l
, i
);
281 if (find_tree(set
, &v
))
289 lclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
294 if (!lclist_set_type(set
))
298 u32
*l
= int_set_get_data(list
);
299 int len
= int_set_get_size(list
);
303 for (i
= 0; i
< len
; i
+= 3) {
304 v
.val
.lc
= lc_get(l
, i
);
305 if (find_tree(set
, &v
))
313 clist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
318 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
321 clist_set_type(set
->val
.t
, &v
);
325 int len
= int_set_get_size(list
);
326 u32
*l
= int_set_get_data(list
);
333 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
334 if ((tree
? !!find_tree(set
->val
.t
, &v
) : int_set_contains(set
->val
.ad
, v
.val
.i
)) == pos
)
338 uint nl
= (k
- tmp
) * sizeof(u32
);
339 if (nl
== list
->length
)
342 struct adata
*res
= adata_empty(pool
, nl
);
343 memcpy(res
->data
, tmp
, nl
);
348 eclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
353 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
356 int len
= int_set_get_size(list
);
357 u32
*l
= int_set_get_data(list
);
363 for (i
= 0; i
< len
; i
+= 2) {
364 v
.val
.ec
= ec_get(l
, i
);
365 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
366 if ((tree
? !!find_tree(set
->val
.t
, &v
) : ec_set_contains(set
->val
.ad
, v
.val
.ec
)) == pos
) {
372 uint nl
= (k
- tmp
) * sizeof(u32
);
373 if (nl
== list
->length
)
376 struct adata
*res
= adata_empty(pool
, nl
);
377 memcpy(res
->data
, tmp
, nl
);
382 lclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
387 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
390 int len
= int_set_get_size(list
);
391 u32
*l
= int_set_get_data(list
);
397 for (i
= 0; i
< len
; i
+= 3) {
398 v
.val
.lc
= lc_get(l
, i
);
399 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
400 if ((tree
? !!find_tree(set
->val
.t
, &v
) : lc_set_contains(set
->val
.ad
, v
.val
.lc
)) == pos
)
404 uint nl
= (k
- tmp
) * sizeof(u32
);
405 if (nl
== list
->length
)
408 struct adata
*res
= adata_empty(pool
, nl
);
409 memcpy(res
->data
, tmp
, nl
);
414 * val_in_range - implement |~| operator
418 * Checks if @v1 is element (|~| operator) of @v2.
421 val_in_range(const struct f_val
*v1
, const struct f_val
*v2
)
423 if ((v1
->type
== T_PATH
) && (v2
->type
== T_PATH_MASK
))
424 return as_path_match(v1
->val
.ad
, v2
->val
.path_mask
);
426 if ((v1
->type
== T_INT
) && (v2
->type
== T_PATH
))
427 return as_path_contains(v2
->val
.ad
, v1
->val
.i
, 1);
429 if (((v1
->type
== T_PAIR
) || (v1
->type
== T_QUAD
)) && (v2
->type
== T_CLIST
))
430 return int_set_contains(v2
->val
.ad
, v1
->val
.i
);
431 /* IP->Quad implicit conversion */
432 if (val_is_ip4(v1
) && (v2
->type
== T_CLIST
))
433 return int_set_contains(v2
->val
.ad
, ipa_to_u32(v1
->val
.ip
));
435 if ((v1
->type
== T_EC
) && (v2
->type
== T_ECLIST
))
436 return ec_set_contains(v2
->val
.ad
, v1
->val
.ec
);
438 if ((v1
->type
== T_LC
) && (v2
->type
== T_LCLIST
))
439 return lc_set_contains(v2
->val
.ad
, v1
->val
.lc
);
441 if ((v1
->type
== T_STRING
) && (v2
->type
== T_STRING
))
442 return patmatch(v2
->val
.s
, v1
->val
.s
);
444 if ((v1
->type
== T_IP
) && (v2
->type
== T_NET
))
445 return ipa_in_netX(v1
->val
.ip
, v2
->val
.net
);
447 if ((v1
->type
== T_NET
) && (v2
->type
== T_NET
))
448 return net_in_netX(v1
->val
.net
, v2
->val
.net
);
450 if ((v1
->type
== T_NET
) && (v2
->type
== T_PREFIX_SET
))
451 return trie_match_net(v2
->val
.ti
, v1
->val
.net
);
453 if (v2
->type
!= T_SET
)
456 /* With integrated Quad<->IP implicit conversion */
457 if ((v1
->type
== v2
->val
.t
->from
.type
) ||
458 ((v1
->type
== T_QUAD
) && val_is_ip4(&(v2
->val
.t
->from
)) && val_is_ip4(&(v2
->val
.t
->to
))))
459 return !!find_tree(v2
->val
.t
, v1
);
461 if (v1
->type
== T_CLIST
)
462 return clist_match_set(v1
->val
.ad
, v2
->val
.t
);
464 if (v1
->type
== T_ECLIST
)
465 return eclist_match_set(v1
->val
.ad
, v2
->val
.t
);
467 if (v1
->type
== T_LCLIST
)
468 return lclist_match_set(v1
->val
.ad
, v2
->val
.t
);
470 if (v1
->type
== T_PATH
)
471 return as_path_match_set(v1
->val
.ad
, v2
->val
.t
);
477 * val_format - format filter value
480 val_format(const struct f_val
*v
, buffer
*buf
)
485 case T_VOID
: buffer_puts(buf
, "(void)"); return;
486 case T_BOOL
: buffer_puts(buf
, v
->val
.i
? "TRUE" : "FALSE"); return;
487 case T_INT
: buffer_print(buf
, "%u", v
->val
.i
); return;
488 case T_STRING
: buffer_print(buf
, "%s", v
->val
.s
); return;
489 case T_IP
: buffer_print(buf
, "%I", v
->val
.ip
); return;
490 case T_NET
: buffer_print(buf
, "%N", v
->val
.net
); return;
491 case T_PAIR
: buffer_print(buf
, "(%u,%u)", v
->val
.i
>> 16, v
->val
.i
& 0xffff); return;
492 case T_QUAD
: buffer_print(buf
, "%R", v
->val
.i
); return;
493 case T_EC
: ec_format(buf2
, v
->val
.ec
); buffer_print(buf
, "%s", buf2
); return;
494 case T_LC
: lc_format(buf2
, v
->val
.lc
); buffer_print(buf
, "%s", buf2
); return;
495 case T_RD
: rd_format(v
->val
.ec
, buf2
, 1024); buffer_print(buf
, "%s", buf2
); return;
496 case T_PREFIX_SET
: trie_format(v
->val
.ti
, buf
); return;
497 case T_SET
: tree_format(v
->val
.t
, buf
); return;
498 case T_ENUM
: buffer_print(buf
, "(enum %x)%u", v
->type
, v
->val
.i
); return;
499 case T_PATH
: as_path_format(v
->val
.ad
, buf2
, 1000); buffer_print(buf
, "(path %s)", buf2
); return;
500 case T_CLIST
: int_set_format(v
->val
.ad
, 1, -1, buf2
, 1000); buffer_print(buf
, "(clist %s)", buf2
); return;
501 case T_ECLIST
: ec_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(eclist %s)", buf2
); return;
502 case T_LCLIST
: lc_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(lclist %s)", buf2
); return;
503 case T_PATH_MASK
: pm_format(v
->val
.path_mask
, buf
); return;
504 default: buffer_print(buf
, "[unknown type %x]", v
->type
); return;
508 static char val_dump_buffer
[1024];
510 val_dump(const struct f_val
*v
) {
512 .start
= val_dump_buffer
,
513 .end
= val_dump_buffer
+ 1024,
517 return val_dump_buffer
;