Skip to content

Commit 08f4f07

Browse files
agelunqdeslandes
authored andcommitted
lib,daemon,cli: use float for meta.probability matcher
Change the meta.probability matcher payload from uint8_t to float, enabling fractional percentage values (e.g., "33.33%", "0.1%"). This aligns meta.probability with meta.flow_probability which already used float. Consolidate the now-identical parse and print functions between the two matchers.
1 parent d053cc4 commit 08f4f07

File tree

7 files changed

+91
-56
lines changed

7 files changed

+91
-56
lines changed

doc/usage/bfcli.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ Meta
539539
- ``meta.probability``
540540
- ``eq``
541541
- ``$PROBABILITY``
542-
- ``$PROBABILITY`` is a valid decimal percentage value (i.e., within [0%, 100%]).
542+
- ``$PROBABILITY`` is a floating-point percentage value (i.e., within [0%, 100%], e.g., "50%" or "33.33%").
543543
* - :rspan:`1` Mark
544544
- :rspan:`1` ``meta.mark``
545545
- ``eq``

src/bfcli/lexer.l

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
%s STATE_MATCHER_META_FLOW_HASH
3333
%s STATE_MATCHER_L4_PROTO
3434
%s STATE_MATCHER_META_PROBA
35-
%s STATE_MATCHER_META_FLOW_PROBA
3635
%s STATE_MATCHER_IPV4_ADDR
3736
%s STATE_MATCHER_IP4_NET
3837
%s STATE_MATCHER_IP4_DSCP
@@ -155,17 +154,8 @@ ip6\.nexthdr { BEGIN(STATE_MATCHER_L4_PROTO); yylval.sval = strdup(yytext); r
155154
}
156155

157156
meta\.probability { BEGIN(STATE_MATCHER_META_PROBA); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
157+
meta\.flow_probability { BEGIN(STATE_MATCHER_META_PROBA); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
158158
<STATE_MATCHER_META_PROBA>{
159-
(eq) { yylval.sval = strdup(yytext); return MATCHER_OP; }
160-
{int}% {
161-
BEGIN(INITIAL);
162-
yylval.sval = strdup(yytext);
163-
return RAW_PAYLOAD;
164-
}
165-
}
166-
167-
meta\.flow_probability { BEGIN(STATE_MATCHER_META_FLOW_PROBA); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
168-
<STATE_MATCHER_META_FLOW_PROBA>{
169159
(eq) { yylval.sval = strdup(yytext); return MATCHER_OP; }
170160
{float}% {
171161
BEGIN(INITIAL);

src/bpfilter/cgen/matcher/meta.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ static int
6767
_bf_matcher_generate_meta_probability(struct bf_program *program,
6868
const struct bf_matcher *matcher)
6969
{
70-
uint8_t proba = *(uint8_t *)bf_matcher_payload(matcher);
70+
float proba = *(float *)bf_matcher_payload(matcher);
7171

7272
EMIT(program, BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32));
7373
EMIT_FIXUP_JMP_NEXT_RULE(
7474
program,
7575
BPF_JMP_IMM(BPF_JGT, BPF_REG_0,
76-
(uint32_t)((uint64_t)UINT32_MAX * (proba / 100.0)), 0));
76+
(uint32_t)((double)UINT32_MAX * (proba / 100.0)), 0));
7777

7878
return 0;
7979
}

src/libbpfilter/matcher.c

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -377,36 +377,6 @@ static int _bf_parse_probability(enum bf_matcher_type type,
377377
assert(payload);
378378
assert(raw_payload);
379379

380-
unsigned long proba;
381-
char *endptr;
382-
383-
proba = strtoul(raw_payload, &endptr, BF_BASE_10);
384-
if (endptr[0] == '%' && endptr[1] == '\0' && proba <= 100) {
385-
*(uint8_t *)payload = (uint8_t)proba;
386-
return 0;
387-
}
388-
389-
bf_err(
390-
"\"%s %s\" expects a valid decimal percentage value (i.e., within [0%%, 100%%]), not '%s'",
391-
bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
392-
393-
return -EINVAL;
394-
}
395-
396-
void _bf_print_probability(const void *payload)
397-
{
398-
assert(payload);
399-
400-
(void)fprintf(stdout, "%" PRIu8 "%%", *(uint8_t *)payload);
401-
}
402-
403-
static int _bf_parse_flow_probability(enum bf_matcher_type type,
404-
enum bf_matcher_op op, void *payload,
405-
const char *raw_payload)
406-
{
407-
assert(payload);
408-
assert(raw_payload);
409-
410380
double proba;
411381
char *endptr;
412382

@@ -424,7 +394,7 @@ static int _bf_parse_flow_probability(enum bf_matcher_type type,
424394
return -EINVAL;
425395
}
426396

427-
static void _bf_print_flow_probability(const void *payload)
397+
static void _bf_print_probability(const void *payload)
428398
{
429399
assert(payload);
430400

@@ -928,7 +898,7 @@ static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
928898
.layer = BF_MATCHER_NO_LAYER,
929899
.ops =
930900
{
931-
BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
901+
BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(float),
932902
_bf_parse_probability,
933903
_bf_print_probability),
934904
},
@@ -972,8 +942,8 @@ static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
972942
.ops =
973943
{
974944
BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(float),
975-
_bf_parse_flow_probability,
976-
_bf_print_flow_probability),
945+
_bf_parse_probability,
946+
_bf_print_probability),
977947
},
978948
},
979949
[BF_MATCHER_IP4_SADDR] =

tests/e2e/matchers/meta_probability.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 0% counter DROP"
66
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 50% counter DROP"
77
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 100% counter DROP"
8+
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 33.33% counter DROP"
9+
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 0.1% counter DROP"
10+
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 99.99% counter DROP"
811

912
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 0 counter DROP")
1013
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq -10% counter DROP")
1114
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 1000 counter DROP")
1215
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 1000% counter DROP")
13-
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq 15.5% counter DROP")
1416
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule meta.probability eq teapot counter DROP")
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
chain test BF_HOOK_XDP ACCEPT
2-
rule meta.probability eq 50% DROP
2+
rule meta.probability eq 50.5% DROP

tests/unit/libbpfilter/matcher.c

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -554,23 +554,42 @@ static void meta_probability(void **state)
554554
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
555555
BF_MATCHER_EQ, "0%"));
556556
assert_non_null(matcher);
557-
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 0);
557+
assert_int_equal(bf_matcher_payload_len(matcher), sizeof(float));
558+
assert_true(*(float *)bf_matcher_payload(matcher) == 0.0f);
558559
bf_matcher_dump(matcher, &prefix);
559560
bf_matcher_free(&matcher);
560561

561562
// Test with 50%
562563
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
563564
BF_MATCHER_EQ, "50%"));
564565
assert_non_null(matcher);
565-
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 50);
566+
assert_true(*(float *)bf_matcher_payload(matcher) == 50.0f);
566567
bf_matcher_dump(matcher, &prefix);
567568
bf_matcher_free(&matcher);
568569

569570
// Test with 100%
570571
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
571572
BF_MATCHER_EQ, "100%"));
572573
assert_non_null(matcher);
573-
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 100);
574+
assert_true(*(float *)bf_matcher_payload(matcher) == 100.0f);
575+
bf_matcher_dump(matcher, &prefix);
576+
bf_matcher_free(&matcher);
577+
578+
// Test with floating-point value
579+
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
580+
BF_MATCHER_EQ, "33.33%"));
581+
assert_non_null(matcher);
582+
assert_true(*(float *)bf_matcher_payload(matcher) > 33.32f);
583+
assert_true(*(float *)bf_matcher_payload(matcher) < 33.34f);
584+
bf_matcher_dump(matcher, &prefix);
585+
bf_matcher_free(&matcher);
586+
587+
// Test with small floating-point value
588+
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
589+
BF_MATCHER_EQ, "0.1%"));
590+
assert_non_null(matcher);
591+
assert_true(*(float *)bf_matcher_payload(matcher) > 0.09f);
592+
assert_true(*(float *)bf_matcher_payload(matcher) < 0.11f);
574593
bf_matcher_dump(matcher, &prefix);
575594
}
576595

@@ -584,6 +603,10 @@ static void meta_probability_invalid(void **state)
584603
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
585604
BF_MATCHER_EQ, "101%"));
586605

606+
// Test with value slightly over 100%
607+
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
608+
BF_MATCHER_EQ, "100.01%"));
609+
587610
// Test without % sign
588611
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
589612
BF_MATCHER_EQ, "50"));
@@ -593,6 +616,46 @@ static void meta_probability_invalid(void **state)
593616
BF_MATCHER_EQ, "-10%"));
594617
}
595618

619+
static void meta_probability_pack_unpack(void **state)
620+
{
621+
_free_bf_matcher_ struct bf_matcher *source = NULL;
622+
_free_bf_matcher_ struct bf_matcher *destination = NULL;
623+
_free_bf_wpack_ bf_wpack_t *wpack = NULL;
624+
_free_bf_rpack_ bf_rpack_t *rpack = NULL;
625+
const void *data;
626+
size_t data_len;
627+
628+
(void)state;
629+
630+
// Test pack/unpack with integer percentage
631+
assert_ok(bf_matcher_new_from_raw(&source, BF_MATCHER_META_PROBABILITY,
632+
BF_MATCHER_EQ, "50%"));
633+
assert_ok(bf_wpack_new(&wpack));
634+
assert_ok(bf_matcher_pack(source, wpack));
635+
assert_ok(bf_wpack_get_data(wpack, &data, &data_len));
636+
637+
assert_ok(bf_rpack_new(&rpack, data, data_len));
638+
assert_ok(bf_matcher_new_from_pack(&destination, bf_rpack_root(rpack)));
639+
640+
assert_true(bft_matcher_equal(source, destination));
641+
bf_matcher_free(&source);
642+
bf_matcher_free(&destination);
643+
bf_wpack_free(&wpack);
644+
bf_rpack_free(&rpack);
645+
646+
// Test pack/unpack with floating-point percentage
647+
assert_ok(bf_matcher_new_from_raw(&source, BF_MATCHER_META_PROBABILITY,
648+
BF_MATCHER_EQ, "33.33%"));
649+
assert_ok(bf_wpack_new(&wpack));
650+
assert_ok(bf_matcher_pack(source, wpack));
651+
assert_ok(bf_wpack_get_data(wpack, &data, &data_len));
652+
653+
assert_ok(bf_rpack_new(&rpack, data, data_len));
654+
assert_ok(bf_matcher_new_from_pack(&destination, bf_rpack_root(rpack)));
655+
656+
assert_true(bft_matcher_equal(source, destination));
657+
}
658+
596659
static void meta_sport_dport(void **state)
597660
{
598661
_free_bf_matcher_ struct bf_matcher *matcher = NULL;
@@ -1231,7 +1294,7 @@ static void print_functions(void **state)
12311294
ops->print(bf_matcher_payload(matcher));
12321295
bf_matcher_free(&matcher);
12331296

1234-
// Test _bf_print_probability via ops
1297+
// Test _bf_print_probability via ops (integer value)
12351298
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
12361299
BF_MATCHER_EQ, "50%"));
12371300
ops = bf_matcher_get_ops(BF_MATCHER_META_PROBABILITY, BF_MATCHER_EQ);
@@ -1240,7 +1303,16 @@ static void print_functions(void **state)
12401303
ops->print(bf_matcher_payload(matcher));
12411304
bf_matcher_free(&matcher);
12421305

1243-
// Test _bf_print_flow_probability via ops (integer value)
1306+
// Test _bf_print_probability via ops (fractional value)
1307+
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_META_PROBABILITY,
1308+
BF_MATCHER_EQ, "33.33%"));
1309+
ops = bf_matcher_get_ops(BF_MATCHER_META_PROBABILITY, BF_MATCHER_EQ);
1310+
assert_non_null(ops);
1311+
assert_non_null(ops->print);
1312+
ops->print(bf_matcher_payload(matcher));
1313+
bf_matcher_free(&matcher);
1314+
1315+
// Test _bf_print_probability via ops (flow_probability, integer value)
12441316
assert_ok(bf_matcher_new_from_raw(
12451317
&matcher, BF_MATCHER_META_FLOW_PROBABILITY, BF_MATCHER_EQ, "50%"));
12461318
ops = bf_matcher_get_ops(BF_MATCHER_META_FLOW_PROBABILITY, BF_MATCHER_EQ);
@@ -1249,7 +1321,7 @@ static void print_functions(void **state)
12491321
ops->print(bf_matcher_payload(matcher));
12501322
bf_matcher_free(&matcher);
12511323

1252-
// Test _bf_print_flow_probability via ops (fractional value)
1324+
// Test _bf_print_probability via ops (flow_probability, fractional value)
12531325
assert_ok(bf_matcher_new_from_raw(
12541326
&matcher, BF_MATCHER_META_FLOW_PROBABILITY, BF_MATCHER_EQ, "33.33%"));
12551327
ops = bf_matcher_get_ops(BF_MATCHER_META_FLOW_PROBABILITY, BF_MATCHER_EQ);
@@ -1659,6 +1731,7 @@ int main(void)
16591731
cmocka_unit_test(meta_l3_proto),
16601732
cmocka_unit_test(meta_probability),
16611733
cmocka_unit_test(meta_probability_invalid),
1734+
cmocka_unit_test(meta_probability_pack_unpack),
16621735
cmocka_unit_test(meta_sport_dport),
16631736
cmocka_unit_test(meta_sport_dport_range),
16641737
cmocka_unit_test(meta_sport_dport_range_invalid),

0 commit comments

Comments
 (0)