]>
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 static const char * const f_type_str
[] = {
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",
48 [T_STRING
] = "string",
49 [T_PATH_MASK
] = "bgpmask",
53 [T_ECLIST
] = "eclist",
55 [T_LCLIST
] = "lclist",
60 f_type_name(enum f_type t
)
62 if (t
< ARRAY_SIZE(f_type_str
))
63 return f_type_str
[t
] ?: "?";
65 if ((t
== T_SET
) || (t
== T_PREFIX_SET
))
72 f_type_element_type(enum f_type t
)
75 case T_CLIST
: return T_PAIR
;
76 case T_ECLIST
: return T_EC
;
77 case T_LCLIST
: return T_LC
;
78 default: return T_VOID
;
82 const struct f_val f_const_empty_path
= {
84 .val
.ad
= &null_adata
,
85 }, f_const_empty_clist
= {
87 .val
.ad
= &null_adata
,
88 }, f_const_empty_eclist
= {
90 .val
.ad
= &null_adata
,
91 }, f_const_empty_lclist
= {
93 .val
.ad
= &null_adata
,
97 adata_empty(struct linpool
*pool
, int l
)
99 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
) + l
);
105 pm_format(const struct f_path_mask
*p
, buffer
*buf
)
109 buffer_puts(buf
, "[= ");
111 for (uint i
=0; i
<p
->len
; i
++)
113 switch(p
->item
[i
].kind
)
116 buffer_print(buf
, "%u ", p
->item
[i
].asn
);
120 buffer_puts(buf
, "? ");
124 buffer_puts(buf
, "* ");
132 buffer_print(buf
, "%u..%u ", p
->item
[i
].from
, p
->item
[i
].to
);
136 tree_format(p
->item
[i
].set
, buf
);
137 buffer_puts(buf
, " ");
144 if (loop
&& (p
->item
[i
].kind
!= PM_LOOP
))
146 buffer_puts(buf
, "+ ");
151 buffer_puts(buf
, "=]");
155 lcomm_cmp(lcomm v1
, lcomm v2
)
157 if (v1
.asn
!= v2
.asn
)
158 return (v1
.asn
> v2
.asn
) ? 1 : -1;
159 if (v1
.ldp1
!= v2
.ldp1
)
160 return (v1
.ldp1
> v2
.ldp1
) ? 1 : -1;
161 if (v1
.ldp2
!= v2
.ldp2
)
162 return (v1
.ldp2
> v2
.ldp2
) ? 1 : -1;
167 * val_compare - compare two values
171 * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on
172 * error. Tree module relies on this giving consistent results so
173 * that it can be used for building balanced trees.
176 val_compare(const struct f_val
*v1
, const struct f_val
*v2
)
178 if (v1
->type
!= v2
->type
) {
179 if (v1
->type
== T_VOID
) /* Hack for else */
181 if (v2
->type
== T_VOID
)
184 /* IP->Quad implicit conversion */
185 if ((v1
->type
== T_QUAD
) && val_is_ip4(v2
))
186 return uint_cmp(v1
->val
.i
, ipa_to_u32(v2
->val
.ip
));
187 if (val_is_ip4(v1
) && (v2
->type
== T_QUAD
))
188 return uint_cmp(ipa_to_u32(v1
->val
.ip
), v2
->val
.i
);
190 debug( "Types do not match in val_compare\n" );
202 return uint_cmp(v1
->val
.i
, v2
->val
.i
);
205 return u64_cmp(v1
->val
.ec
, v2
->val
.ec
);
207 return lcomm_cmp(v1
->val
.lc
, v2
->val
.lc
);
209 return ipa_compare(v1
->val
.ip
, v2
->val
.ip
);
211 return net_compare(v1
->val
.net
, v2
->val
.net
);
213 return strcmp(v1
->val
.s
, v2
->val
.s
);
220 pmi_same(const struct f_path_mask_item
*mi1
, const struct f_path_mask_item
*mi2
)
222 if (mi1
->kind
!= mi2
->kind
)
227 if (mi1
->asn
!= mi2
->asn
)
231 if (!f_same(mi1
->expr
, mi2
->expr
))
235 if (mi1
->from
!= mi2
->from
)
237 if (mi1
->to
!= mi2
->to
)
241 if (!same_tree(mi1
->set
, mi2
->set
))
250 pm_same(const struct f_path_mask
*m1
, const struct f_path_mask
*m2
)
252 if (m1
->len
!= m2
->len
)
255 for (uint i
=0; i
<m1
->len
; i
++)
256 if (!pmi_same(&(m1
->item
[i
]), &(m2
->item
[i
])))
263 * val_same - compare two values
267 * Compares two values and returns 1 if they are same and 0 if not.
268 * Comparison of values of different types is valid and returns 0.
271 val_same(const struct f_val
*v1
, const struct f_val
*v2
)
275 rc
= val_compare(v1
, v2
);
276 if (rc
!= F_CMP_ERROR
)
279 if (v1
->type
!= v2
->type
)
284 return pm_same(v1
->val
.path_mask
, v2
->val
.path_mask
);
285 case T_PATH_MASK_ITEM
:
286 return pmi_same(&(v1
->val
.pmi
), &(v2
->val
.pmi
));
291 return adata_same(v1
->val
.ad
, v2
->val
.ad
);
293 return same_tree(v1
->val
.t
, v2
->val
.t
);
295 return trie_same(v1
->val
.ti
, v2
->val
.ti
);
297 bug("Invalid type in val_same(): %x", v1
->type
);
302 clist_set_type(const struct f_tree
*set
, struct f_val
*v
)
304 switch (set
->from
.type
)
315 if (val_is_ip4(&(set
->from
)) && val_is_ip4(&(set
->to
)))
328 clist_match_set(const struct adata
*clist
, const struct f_tree
*set
)
334 if (!clist_set_type(set
, &v
))
337 u32
*l
= (u32
*) clist
->data
;
338 u32
*end
= l
+ clist
->length
/4;
342 if (find_tree(set
, &v
))
349 eclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
354 if (!eclist_set_type(set
))
358 u32
*l
= int_set_get_data(list
);
359 int len
= int_set_get_size(list
);
363 for (i
= 0; i
< len
; i
+= 2) {
364 v
.val
.ec
= ec_get(l
, i
);
365 if (find_tree(set
, &v
))
373 lclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
378 if (!lclist_set_type(set
))
382 u32
*l
= int_set_get_data(list
);
383 int len
= int_set_get_size(list
);
387 for (i
= 0; i
< len
; i
+= 3) {
388 v
.val
.lc
= lc_get(l
, i
);
389 if (find_tree(set
, &v
))
397 clist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
402 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
405 clist_set_type(set
->val
.t
, &v
);
409 int len
= int_set_get_size(list
);
410 u32
*l
= int_set_get_data(list
);
417 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
418 if ((tree
? !!find_tree(set
->val
.t
, &v
) : int_set_contains(set
->val
.ad
, v
.val
.i
)) == pos
)
422 uint nl
= (k
- tmp
) * sizeof(u32
);
423 if (nl
== list
->length
)
426 struct adata
*res
= adata_empty(pool
, nl
);
427 memcpy(res
->data
, tmp
, nl
);
432 eclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
437 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
440 int len
= int_set_get_size(list
);
441 u32
*l
= int_set_get_data(list
);
447 for (i
= 0; i
< len
; i
+= 2) {
448 v
.val
.ec
= ec_get(l
, i
);
449 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
450 if ((tree
? !!find_tree(set
->val
.t
, &v
) : ec_set_contains(set
->val
.ad
, v
.val
.ec
)) == pos
) {
456 uint nl
= (k
- tmp
) * sizeof(u32
);
457 if (nl
== list
->length
)
460 struct adata
*res
= adata_empty(pool
, nl
);
461 memcpy(res
->data
, tmp
, nl
);
466 lclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
471 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
474 int len
= int_set_get_size(list
);
475 u32
*l
= int_set_get_data(list
);
481 for (i
= 0; i
< len
; i
+= 3) {
482 v
.val
.lc
= lc_get(l
, i
);
483 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
484 if ((tree
? !!find_tree(set
->val
.t
, &v
) : lc_set_contains(set
->val
.ad
, v
.val
.lc
)) == pos
)
488 uint nl
= (k
- tmp
) * sizeof(u32
);
489 if (nl
== list
->length
)
492 struct adata
*res
= adata_empty(pool
, nl
);
493 memcpy(res
->data
, tmp
, nl
);
498 * val_in_range - implement |~| operator
502 * Checks if @v1 is element (|~| operator) of @v2.
505 val_in_range(const struct f_val
*v1
, const struct f_val
*v2
)
507 if ((v1
->type
== T_PATH
) && (v2
->type
== T_PATH_MASK
))
508 return as_path_match(v1
->val
.ad
, v2
->val
.path_mask
);
510 if ((v1
->type
== T_INT
) && (v2
->type
== T_PATH
))
511 return as_path_contains(v2
->val
.ad
, v1
->val
.i
, 1);
513 if (((v1
->type
== T_PAIR
) || (v1
->type
== T_QUAD
)) && (v2
->type
== T_CLIST
))
514 return int_set_contains(v2
->val
.ad
, v1
->val
.i
);
515 /* IP->Quad implicit conversion */
516 if (val_is_ip4(v1
) && (v2
->type
== T_CLIST
))
517 return int_set_contains(v2
->val
.ad
, ipa_to_u32(v1
->val
.ip
));
519 if ((v1
->type
== T_EC
) && (v2
->type
== T_ECLIST
))
520 return ec_set_contains(v2
->val
.ad
, v1
->val
.ec
);
522 if ((v1
->type
== T_LC
) && (v2
->type
== T_LCLIST
))
523 return lc_set_contains(v2
->val
.ad
, v1
->val
.lc
);
525 if ((v1
->type
== T_STRING
) && (v2
->type
== T_STRING
))
526 return patmatch(v2
->val
.s
, v1
->val
.s
);
528 if ((v1
->type
== T_IP
) && (v2
->type
== T_NET
))
529 return ipa_in_netX(v1
->val
.ip
, v2
->val
.net
);
531 if ((v1
->type
== T_NET
) && (v2
->type
== T_NET
))
532 return net_in_netX(v1
->val
.net
, v2
->val
.net
);
534 if ((v1
->type
== T_NET
) && (v2
->type
== T_PREFIX_SET
))
535 return trie_match_net(v2
->val
.ti
, v1
->val
.net
);
537 if (v2
->type
!= T_SET
)
540 /* With integrated Quad<->IP implicit conversion */
541 if ((v1
->type
== v2
->val
.t
->from
.type
) ||
542 ((v1
->type
== T_QUAD
) && val_is_ip4(&(v2
->val
.t
->from
)) && val_is_ip4(&(v2
->val
.t
->to
))))
543 return !!find_tree(v2
->val
.t
, v1
);
545 if (v1
->type
== T_CLIST
)
546 return clist_match_set(v1
->val
.ad
, v2
->val
.t
);
548 if (v1
->type
== T_ECLIST
)
549 return eclist_match_set(v1
->val
.ad
, v2
->val
.t
);
551 if (v1
->type
== T_LCLIST
)
552 return lclist_match_set(v1
->val
.ad
, v2
->val
.t
);
554 if (v1
->type
== T_PATH
)
555 return as_path_match_set(v1
->val
.ad
, v2
->val
.t
);
561 * val_format - format filter value
564 val_format(const struct f_val
*v
, buffer
*buf
)
569 case T_VOID
: buffer_puts(buf
, "(void)"); return;
570 case T_BOOL
: buffer_puts(buf
, v
->val
.i
? "TRUE" : "FALSE"); return;
571 case T_INT
: buffer_print(buf
, "%u", v
->val
.i
); return;
572 case T_STRING
: buffer_print(buf
, "%s", v
->val
.s
); return;
573 case T_IP
: buffer_print(buf
, "%I", v
->val
.ip
); return;
574 case T_NET
: buffer_print(buf
, "%N", v
->val
.net
); return;
575 case T_PAIR
: buffer_print(buf
, "(%u,%u)", v
->val
.i
>> 16, v
->val
.i
& 0xffff); return;
576 case T_QUAD
: buffer_print(buf
, "%R", v
->val
.i
); return;
577 case T_EC
: ec_format(buf2
, v
->val
.ec
); buffer_print(buf
, "%s", buf2
); return;
578 case T_LC
: lc_format(buf2
, v
->val
.lc
); buffer_print(buf
, "%s", buf2
); return;
579 case T_RD
: rd_format(v
->val
.ec
, buf2
, 1024); buffer_print(buf
, "%s", buf2
); return;
580 case T_PREFIX_SET
: trie_format(v
->val
.ti
, buf
); return;
581 case T_SET
: tree_format(v
->val
.t
, buf
); return;
582 case T_ENUM
: buffer_print(buf
, "(enum %x)%u", v
->type
, v
->val
.i
); return;
583 case T_PATH
: as_path_format(v
->val
.ad
, buf2
, 1000); buffer_print(buf
, "(path %s)", buf2
); return;
584 case T_CLIST
: int_set_format(v
->val
.ad
, 1, -1, buf2
, 1000); buffer_print(buf
, "(clist %s)", buf2
); return;
585 case T_ECLIST
: ec_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(eclist %s)", buf2
); return;
586 case T_LCLIST
: lc_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(lclist %s)", buf2
); return;
587 case T_PATH_MASK
: pm_format(v
->val
.path_mask
, buf
); return;
588 default: buffer_print(buf
, "[unknown type %x]", v
->type
); return;
593 val_format_str(struct linpool
*lp
, const struct f_val
*v
) {
597 return lp_strdup(lp
, b
.start
);
601 static char val_dump_buffer
[1024];
603 val_dump(const struct f_val
*v
) {
605 .start
= val_dump_buffer
,
606 .end
= val_dump_buffer
+ 1024,
610 return val_dump_buffer
;