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
[] = {
37 [T_ENUM_RTS
] = "enum rts",
38 [T_ENUM_BGP_ORIGIN
] = "enum bgp_origin",
39 [T_ENUM_SCOPE
] = "enum scope",
40 [T_ENUM_RTC
] = "enum rtc",
41 [T_ENUM_RTD
] = "enum rtd",
42 [T_ENUM_ROA
] = "enum roa",
43 [T_ENUM_NETTYPE
] = "enum nettype",
44 [T_ENUM_RA_PREFERENCE
] = "enum ra_preference",
45 [T_ENUM_AF
] = "enum af",
49 [T_STRING
] = "string",
50 [T_BYTESTRING
] = "bytestring",
51 [T_PATH_MASK
] = "bgpmask",
55 [T_ECLIST
] = "eclist",
57 [T_LCLIST
] = "lclist",
61 [T_ROUTES_BLOCK
] = "block of routes",
65 f_type_name(enum f_type t
)
67 if (t
< ARRAY_SIZE(f_type_str
))
68 return f_type_str
[t
] ?: "?";
70 if ((t
== T_SET
) || (t
== T_PREFIX_SET
))
77 f_type_element_type(enum f_type t
)
80 case T_PATH
: return T_INT
;
81 case T_CLIST
: return T_PAIR
;
82 case T_ECLIST
: return T_EC
;
83 case T_LCLIST
: return T_LC
;
84 case T_ROUTES_BLOCK
: return T_ROUTE
;
85 default: return T_VOID
;
89 const struct f_trie f_const_empty_trie
= { .ipv4
= -1, };
90 const struct f_val f_const_empty_prefix_set
= {
92 .val
.ti
= &f_const_empty_trie
,
96 adata_empty(struct linpool
*pool
, int l
)
98 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
) + l
);
104 pm_format(const struct f_path_mask
*p
, buffer
*buf
)
108 buffer_puts(buf
, "[= ");
110 for (uint i
=0; i
<p
->len
; i
++)
112 switch(p
->item
[i
].kind
)
115 buffer_print(buf
, "%u ", p
->item
[i
].asn
);
119 buffer_puts(buf
, "? ");
123 buffer_puts(buf
, "* ");
131 buffer_print(buf
, "%u..%u ", p
->item
[i
].from
, p
->item
[i
].to
);
135 tree_format(p
->item
[i
].set
, buf
);
136 buffer_puts(buf
, " ");
143 if (loop
&& (p
->item
[i
].kind
!= PM_LOOP
))
145 buffer_puts(buf
, "+ ");
150 buffer_puts(buf
, "=]");
154 lcomm_cmp(lcomm v1
, lcomm v2
)
156 if (v1
.asn
!= v2
.asn
)
157 return (v1
.asn
> v2
.asn
) ? 1 : -1;
158 if (v1
.ldp1
!= v2
.ldp1
)
159 return (v1
.ldp1
> v2
.ldp1
) ? 1 : -1;
160 if (v1
.ldp2
!= v2
.ldp2
)
161 return (v1
.ldp2
> v2
.ldp2
) ? 1 : -1;
166 * val_compare - compare two values
170 * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on
171 * error. Tree module relies on this giving consistent results so
172 * that it can be used for building balanced trees.
175 val_compare(const struct f_val
*v1
, const struct f_val
*v2
)
177 if (v1
->type
!= v2
->type
) {
178 if (v1
->type
== T_VOID
) /* Hack for else */
180 if (v2
->type
== T_VOID
)
183 /* IP->Quad implicit conversion */
184 if ((v1
->type
== T_QUAD
) && val_is_ip4(v2
))
185 return uint_cmp(v1
->val
.i
, ipa_to_u32(v2
->val
.ip
));
186 if (val_is_ip4(v1
) && (v2
->type
== T_QUAD
))
187 return uint_cmp(ipa_to_u32(v1
->val
.ip
), v2
->val
.i
);
189 DBG( "Types do not match in val_compare\n" );
201 return uint_cmp(v1
->val
.i
, v2
->val
.i
);
204 return u64_cmp(v1
->val
.ec
, v2
->val
.ec
);
206 return lcomm_cmp(v1
->val
.lc
, v2
->val
.lc
);
208 return ipa_compare(v1
->val
.ip
, v2
->val
.ip
);
210 return net_compare(v1
->val
.net
, v2
->val
.net
);
212 return strcmp(v1
->val
.s
, v2
->val
.s
);
214 return as_path_compare(v1
->val
.ad
, v2
->val
.ad
);
224 bs_same(const struct adata
*bs1
, const struct adata
*bs2
)
226 return (bs1
->length
== bs2
->length
) && !memcmp(bs1
->data
, bs2
->data
, bs1
->length
);
230 pmi_same(const struct f_path_mask_item
*mi1
, const struct f_path_mask_item
*mi2
)
232 if (mi1
->kind
!= mi2
->kind
)
237 if (mi1
->asn
!= mi2
->asn
)
241 if (!f_same(mi1
->expr
, mi2
->expr
))
245 if (mi1
->from
!= mi2
->from
)
247 if (mi1
->to
!= mi2
->to
)
251 if (!same_tree(mi1
->set
, mi2
->set
))
260 pm_same(const struct f_path_mask
*m1
, const struct f_path_mask
*m2
)
262 if (m1
->len
!= m2
->len
)
265 for (uint i
=0; i
<m1
->len
; i
++)
266 if (!pmi_same(&(m1
->item
[i
]), &(m2
->item
[i
])))
273 * val_same - compare two values
277 * Compares two values and returns 1 if they are same and 0 if not.
278 * Comparison of values of different types is valid and returns 0.
281 val_same(const struct f_val
*v1
, const struct f_val
*v2
)
285 rc
= val_compare(v1
, v2
);
286 if (rc
!= F_CMP_ERROR
)
289 if (v1
->type
!= v2
->type
)
294 return bs_same(v1
->val
.bs
, v2
->val
.bs
);
296 return pm_same(v1
->val
.path_mask
, v2
->val
.path_mask
);
297 case T_PATH_MASK_ITEM
:
298 return pmi_same(&(v1
->val
.pmi
), &(v2
->val
.pmi
));
303 return adata_same(v1
->val
.ad
, v2
->val
.ad
);
305 return same_tree(v1
->val
.t
, v2
->val
.t
);
307 return trie_same(v1
->val
.ti
, v2
->val
.ti
);
309 return v1
->val
.rte
== v2
->val
.rte
;
311 return v1
->val
.ad
== v2
->val
.ad
;
313 bug("Invalid type in val_same(): %x", v1
->type
);
318 clist_set_type(const struct f_tree
*set
, struct f_val
*v
)
326 switch (set
->from
.type
)
337 if (val_is_ip4(&(set
->from
)) && val_is_ip4(&(set
->to
)))
350 clist_match_set(const struct adata
*clist
, const struct f_tree
*set
)
356 if (!clist_set_type(set
, &v
))
359 u32
*l
= (u32
*) clist
->data
;
360 u32
*end
= l
+ clist
->length
/4;
364 if (find_tree(set
, &v
))
371 eclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
376 if (!eclist_set_type(set
))
380 u32
*l
= int_set_get_data(list
);
381 int len
= int_set_get_size(list
);
385 for (i
= 0; i
< len
; i
+= 2) {
386 v
.val
.ec
= ec_get(l
, i
);
387 if (find_tree(set
, &v
))
395 lclist_match_set(const struct adata
*list
, const struct f_tree
*set
)
400 if (!lclist_set_type(set
))
404 u32
*l
= int_set_get_data(list
);
405 int len
= int_set_get_size(list
);
409 for (i
= 0; i
< len
; i
+= 3) {
410 v
.val
.lc
= lc_get(l
, i
);
411 if (find_tree(set
, &v
))
419 clist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
424 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
427 clist_set_type(set
->val
.t
, &v
);
431 int len
= int_set_get_size(list
);
432 u32
*l
= int_set_get_data(list
);
439 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
440 if ((tree
? !!find_tree(set
->val
.t
, &v
) : int_set_contains(set
->val
.ad
, v
.val
.i
)) == pos
)
444 uint nl
= (k
- tmp
) * sizeof(u32
);
445 if (nl
== list
->length
)
448 struct adata
*res
= adata_empty(pool
, nl
);
449 memcpy(res
->data
, tmp
, nl
);
454 eclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
459 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
462 int len
= int_set_get_size(list
);
463 u32
*l
= int_set_get_data(list
);
469 for (i
= 0; i
< len
; i
+= 2) {
470 v
.val
.ec
= ec_get(l
, i
);
471 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
472 if ((tree
? !!find_tree(set
->val
.t
, &v
) : ec_set_contains(set
->val
.ad
, v
.val
.ec
)) == pos
) {
478 uint nl
= (k
- tmp
) * sizeof(u32
);
479 if (nl
== list
->length
)
482 struct adata
*res
= adata_empty(pool
, nl
);
483 memcpy(res
->data
, tmp
, nl
);
488 lclist_filter(struct linpool
*pool
, const struct adata
*list
, const struct f_val
*set
, int pos
)
493 int tree
= (set
->type
== T_SET
); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
496 int len
= int_set_get_size(list
);
497 u32
*l
= int_set_get_data(list
);
503 for (i
= 0; i
< len
; i
+= 3) {
504 v
.val
.lc
= lc_get(l
, i
);
505 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
506 if ((tree
? !!find_tree(set
->val
.t
, &v
) : lc_set_contains(set
->val
.ad
, v
.val
.lc
)) == pos
)
510 uint nl
= (k
- tmp
) * sizeof(u32
);
511 if (nl
== list
->length
)
514 struct adata
*res
= adata_empty(pool
, nl
);
515 memcpy(res
->data
, tmp
, nl
);
520 * val_in_range - implement |~| operator
524 * Checks if @v1 is element (|~| operator) of @v2.
527 val_in_range(const struct f_val
*v1
, const struct f_val
*v2
)
529 if ((v1
->type
== T_PATH
) && (v2
->type
== T_PATH_MASK
))
530 return as_path_match(v1
->val
.ad
, v2
->val
.path_mask
);
532 if ((v1
->type
== T_INT
) && (v2
->type
== T_PATH
))
533 return as_path_contains(v2
->val
.ad
, v1
->val
.i
, 1);
535 if (((v1
->type
== T_PAIR
) || (v1
->type
== T_QUAD
)) && (v2
->type
== T_CLIST
))
536 return int_set_contains(v2
->val
.ad
, v1
->val
.i
);
537 /* IP->Quad implicit conversion */
538 if (val_is_ip4(v1
) && (v2
->type
== T_CLIST
))
539 return int_set_contains(v2
->val
.ad
, ipa_to_u32(v1
->val
.ip
));
541 if ((v1
->type
== T_EC
) && (v2
->type
== T_ECLIST
))
542 return ec_set_contains(v2
->val
.ad
, v1
->val
.ec
);
544 if ((v1
->type
== T_LC
) && (v2
->type
== T_LCLIST
))
545 return lc_set_contains(v2
->val
.ad
, v1
->val
.lc
);
547 if ((v1
->type
== T_STRING
) && (v2
->type
== T_STRING
))
548 return patmatch(v2
->val
.s
, v1
->val
.s
);
550 if ((v1
->type
== T_IP
) && (v2
->type
== T_NET
))
551 return ipa_in_netX(v1
->val
.ip
, v2
->val
.net
);
553 if ((v1
->type
== T_NET
) && (v2
->type
== T_NET
))
554 return net_in_netX(v1
->val
.net
, v2
->val
.net
);
556 if ((v1
->type
== T_NET
) && (v2
->type
== T_PREFIX_SET
))
557 return trie_match_net(v2
->val
.ti
, v1
->val
.net
);
559 if (v2
->type
!= T_SET
)
565 /* With integrated Quad<->IP implicit conversion */
566 if ((v1
->type
== v2
->val
.t
->from
.type
) ||
567 ((v1
->type
== T_QUAD
) && val_is_ip4(&(v2
->val
.t
->from
)) && val_is_ip4(&(v2
->val
.t
->to
))))
568 return !!find_tree(v2
->val
.t
, v1
);
570 if (v1
->type
== T_CLIST
)
571 return clist_match_set(v1
->val
.ad
, v2
->val
.t
);
573 if (v1
->type
== T_ECLIST
)
574 return eclist_match_set(v1
->val
.ad
, v2
->val
.t
);
576 if (v1
->type
== T_LCLIST
)
577 return lclist_match_set(v1
->val
.ad
, v2
->val
.t
);
579 if (v1
->type
== T_PATH
)
580 return as_path_match_set(v1
->val
.ad
, v2
->val
.t
);
586 * rte_format - format route information
589 rte_format(const struct rte
*rte
, buffer
*buf
)
592 buffer_print(buf
, "Route [%d] to %N from %s.%s via %s",
593 rte
->src
->global_id
, rte
->net
->n
.addr
,
594 rte
->sender
->proto
->name
, rte
->sender
->name
,
595 rte
->src
->proto
->name
);
597 buffer_puts(buf
, "[No route]");
601 rte_block_format(const struct rte
*rte
, buffer
*buf
)
603 buffer_print(buf
, "Block of routes:");
608 buffer_print(buf
, "%s%d: ", i
? "; " : " ", i
);
609 rte_format(rte
, buf
);
616 * val_format - format filter value
619 val_format(const struct f_val
*v
, buffer
*buf
)
624 case T_VOID
: buffer_puts(buf
, "(void)"); return;
625 case T_BOOL
: buffer_puts(buf
, v
->val
.i
? "TRUE" : "FALSE"); return;
626 case T_INT
: buffer_print(buf
, "%u", v
->val
.i
); return;
627 case T_STRING
: buffer_print(buf
, "%s", v
->val
.s
); return;
628 case T_BYTESTRING
: bstrbintohex(v
->val
.bs
->data
, v
->val
.bs
->length
, buf2
, 1000, ':'); buffer_print(buf
, "%s", buf2
); return;
629 case T_IP
: buffer_print(buf
, "%I", v
->val
.ip
); return;
630 case T_NET
: buffer_print(buf
, "%N", v
->val
.net
); return;
631 case T_PAIR
: buffer_print(buf
, "(%u,%u)", v
->val
.i
>> 16, v
->val
.i
& 0xffff); return;
632 case T_QUAD
: buffer_print(buf
, "%R", v
->val
.i
); return;
633 case T_EC
: ec_format(buf2
, v
->val
.ec
); buffer_print(buf
, "%s", buf2
); return;
634 case T_LC
: lc_format(buf2
, v
->val
.lc
); buffer_print(buf
, "%s", buf2
); return;
635 case T_RD
: rd_format(v
->val
.ec
, buf2
, 1024); buffer_print(buf
, "%s", buf2
); return;
636 case T_PREFIX_SET
: trie_format(v
->val
.ti
, buf
); return;
637 case T_SET
: tree_format(v
->val
.t
, buf
); return;
638 case T_ENUM
: buffer_print(buf
, "(enum %x)%u", v
->type
, v
->val
.i
); return;
639 case T_PATH
: as_path_format(v
->val
.ad
, buf2
, 1000); buffer_print(buf
, "(path %s)", buf2
); return;
640 case T_CLIST
: int_set_format(v
->val
.ad
, 1, -1, buf2
, 1000); buffer_print(buf
, "(clist %s)", buf2
); return;
641 case T_ECLIST
: ec_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(eclist %s)", buf2
); return;
642 case T_LCLIST
: lc_set_format(v
->val
.ad
, -1, buf2
, 1000); buffer_print(buf
, "(lclist %s)", buf2
); return;
643 case T_PATH_MASK
: pm_format(v
->val
.path_mask
, buf
); return;
644 case T_ROUTE
: rte_format(v
->val
.rte
, buf
); return;
645 case T_ROUTES_BLOCK
: rte_block_format(v
->val
.rte
, buf
); return;
646 default: buffer_print(buf
, "[unknown type %x]", v
->type
); return;
651 val_format_str(struct linpool
*lp
, const struct f_val
*v
) {
655 return lp_strdup(lp
, b
.start
);
659 static char val_dump_buffer
[1024];
661 val_dump(const struct f_val
*v
) {
663 .start
= val_dump_buffer
,
664 .end
= val_dump_buffer
+ 1024,
668 return val_dump_buffer
;