]>
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 pmi_same(const struct f_path_mask_item
*mi1
, const struct f_path_mask_item
*mi2
)
152 if (mi1
->kind
!= mi2
->kind
)
157 if (mi1
->asn
!= mi2
->asn
)
161 if (!f_same(mi1
->expr
, mi2
->expr
))
165 if (mi1
->from
!= mi2
->from
)
167 if (mi1
->to
!= mi2
->to
)
176 pm_same(const struct f_path_mask
*m1
, const struct f_path_mask
*m2
)
178 if (m1
->len
!= m2
->len
)
180 for (uint i
=0; i
<m1
->len
; i
++)
181 if (!pmi_same(&(m1
->item
[i
]), &(m2
->item
[i
])))
188 * val_same - compare two values
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.
196 val_same(const struct f_val
*v1
, const struct f_val
*v2
)
200 rc
= val_compare(v1
, v2
);
201 if (rc
!= F_CMP_ERROR
)
204 if (v1
->type
!= v2
->type
)
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
));
216 return adata_same(v1
->val
.ad
, v2
->val
.ad
);
218 return same_tree(v1
->val
.t
, v2
->val
.t
);
220 return trie_same(v1
->val
.ti
, v2
->val
.ti
);
222 bug("Invalid type in val_same(): %x", v1
->type
);
227 clist_set_type(const struct f_tree
*set
, struct f_val
*v
)
229 switch (set
->from
.type
)
240 if (val_is_ip4(&(set
->from
)) && val_is_ip4(&(set
->to
)))
253 clist_match_set(const struct adata
*clist
, const struct f_tree
*set
)
259 if (!clist_set_type(set
, &v
))
262 u32
*l
= (u32
*) clist
->data
;
263 u32
*end
= l
+ clist
->length
/4;
267 if (find_tree(set
, &v
))
274 eclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
279 if (!eclist_set_type(set
))
283 u32
*l
= int_set_get_data(list
);
284 int len
= int_set_get_size(list
);
288 for (i
= 0; i
< len
; i
+= 2) {
289 v
.val
.ec
= ec_get(l
, i
);
290 if (find_tree(set
, &v
))
298 lclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
303 if (!lclist_set_type(set
))
307 u32
*l
= int_set_get_data(list
);
308 int len
= int_set_get_size(list
);
312 for (i
= 0; i
< len
; i
+= 3) {
313 v
.val
.lc
= lc_get(l
, i
);
314 if (find_tree(set
, &v
))
322 clist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
327 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
330 clist_set_type(set
->val
.t
, &v
);
334 int len
= int_set_get_size(list
);
335 u32
*l
= int_set_get_data(list
);
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
)
347 uint nl
= (k
- tmp
) * sizeof(u32
);
348 if (nl
== list
->length
)
351 struct adata
*res
= adata_empty(pool
, nl
);
352 memcpy(res
->data
, tmp
, nl
);
357 eclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
362 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
365 int len
= int_set_get_size(list
);
366 u32
*l
= int_set_get_data(list
);
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
) {
381 uint nl
= (k
- tmp
) * sizeof(u32
);
382 if (nl
== list
->length
)
385 struct adata
*res
= adata_empty(pool
, nl
);
386 memcpy(res
->data
, tmp
, nl
);
391 lclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
396 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
399 int len
= int_set_get_size(list
);
400 u32
*l
= int_set_get_data(list
);
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
)
413 uint nl
= (k
- tmp
) * sizeof(u32
);
414 if (nl
== list
->length
)
417 struct adata
*res
= adata_empty(pool
, nl
);
418 memcpy(res
->data
, tmp
, nl
);
423 * val_in_range - implement |~| operator
427 * Checks if @v1 is element (|~| operator) of @v2.
430 val_in_range(const struct f_val
*v1
, const struct f_val
*v2
)
432 if ((v1
->type
== T_PATH
) && (v2
->type
== T_PATH_MASK
))
433 return as_path_match(v1
->val
.ad
, v2
->val
.path_mask
);
435 if ((v1
->type
== T_INT
) && (v2
->type
== T_PATH
))
436 return as_path_contains(v2
->val
.ad
, v1
->val
.i
, 1);
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
));
444 if ((v1
->type
== T_EC
) && (v2
->type
== T_ECLIST
))
445 return ec_set_contains(v2
->val
.ad
, v1
->val
.ec
);
447 if ((v1
->type
== T_LC
) && (v2
->type
== T_LCLIST
))
448 return lc_set_contains(v2
->val
.ad
, v1
->val
.lc
);
450 if ((v1
->type
== T_STRING
) && (v2
->type
== T_STRING
))
451 return patmatch(v2
->val
.s
, v1
->val
.s
);
453 if ((v1
->type
== T_IP
) && (v2
->type
== T_NET
))
454 return ipa_in_netX(v1
->val
.ip
, v2
->val
.net
);
456 if ((v1
->type
== T_NET
) && (v2
->type
== T_NET
))
457 return net_in_netX(v1
->val
.net
, v2
->val
.net
);
459 if ((v1
->type
== T_NET
) && (v2
->type
== T_PREFIX_SET
))
460 return trie_match_net(v2
->val
.ti
, v1
->val
.net
);
462 if (v2
->type
!= T_SET
)
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
);
470 if (v1
->type
== T_CLIST
)
471 return clist_match_set(v1
->val
.ad
, v2
->val
.t
);
473 if (v1
->type
== T_ECLIST
)
474 return eclist_match_set(v1
->val
.ad
, v2
->val
.t
);
476 if (v1
->type
== T_LCLIST
)
477 return lclist_match_set(v1
->val
.ad
, v2
->val
.t
);
479 if (v1
->type
== T_PATH
)
480 return as_path_match_set(v1
->val
.ad
, v2
->val
.t
);
486 * val_format - format filter value
489 val_format(const struct f_val
*v
, buffer
*buf
)
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;
517 static char val_dump_buffer
[1024];
519 val_dump(const struct f_val
*v
) {
521 .start
= val_dump_buffer
,
522 .end
= val_dump_buffer
+ 1024,
526 return val_dump_buffer
;