Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/bfcli/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
%s STATE_MATCHER_IP4_DSCP
%s STATE_MATCHER_IP6_ADDR
%s STATE_MATCHER_IP6_NET
%s STATE_MATCHER_IP6_DSCP
%s STATE_MATCHER_PORT
%s STATE_MATCHER_ICMP_TYPE
%s STATE_MATCHER_ICMP_CODE
Expand Down Expand Up @@ -216,6 +217,16 @@ ip6\.(s|d)net { BEGIN(STATE_MATCHER_IP6_NET); yylval.sval = strdup(yytext)
}
}

ip6\.dscp { BEGIN(STATE_MATCHER_IP6_DSCP); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
<STATE_MATCHER_IP6_DSCP>{
(eq|not) { yylval.sval = strdup(yytext); return MATCHER_OP; }
{int} {
BEGIN(INITIAL);
yylval.sval = strdup(yytext);
return RAW_PAYLOAD;
}
}

meta\.(s|d)port { BEGIN(STATE_MATCHER_PORT); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
tcp\.(s|d)port { BEGIN(STATE_MATCHER_PORT); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
udp\.(s|d)port { BEGIN(STATE_MATCHER_PORT); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
Expand Down
31 changes: 31 additions & 0 deletions src/bpfilter/cgen/matcher/ip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/in.h>
#include <linux/ipv6.h>

#include <assert.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
Expand Down Expand Up @@ -293,6 +294,33 @@ static int _bf_matcher_generate_ip6_nexthdr(struct bf_program *program,
return 0;
}

static int _bf_matcher_generate_ip6_dscp(struct bf_program *program,
const struct bf_matcher *matcher)
{
uint8_t dscp;

assert(program);
assert(matcher);

dscp = *(uint8_t *)bf_matcher_payload(matcher);

/* IPv6 DSCP (traffic class) spans bits 4-11 of the header:
* Byte 0: version (4 bits) | dscp_high (4 bits)
* Byte 1: dscp_low (4 bits) | flow_label_high (4 bits)
* Load 2 bytes, mask with 0x0ff0, compare against dscp << 4. */

EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6, 0));
EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x0ff0));

EMIT_FIXUP_JMP_NEXT_RULE(
program,
BPF_JMP_IMM(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
BPF_JEQ,
BPF_REG_1, (uint16_t)dscp << 4, 0));

return 0;
}

int bf_matcher_generate_ip6(struct bf_program *program,
const struct bf_matcher *matcher)
{
Expand All @@ -316,6 +344,9 @@ int bf_matcher_generate_ip6(struct bf_program *program,
case BF_MATCHER_IP6_NEXTHDR:
r = _bf_matcher_generate_ip6_nexthdr(program, matcher);
break;
case BF_MATCHER_IP6_DSCP:
r = _bf_matcher_generate_ip6_dscp(program, matcher);
break;
default:
return bf_err_r(-EINVAL, "unknown matcher type %d",
bf_matcher_get_type(matcher));
Expand Down
1 change: 1 addition & 0 deletions src/bpfilter/cgen/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ static int _bf_program_generate_rule(struct bf_program *program,
case BF_MATCHER_IP6_DADDR:
case BF_MATCHER_IP6_DNET:
case BF_MATCHER_IP6_NEXTHDR:
case BF_MATCHER_IP6_DSCP:
r = bf_matcher_generate_ip6(program, matcher);
if (r)
return r;
Expand Down
2 changes: 2 additions & 0 deletions src/libbpfilter/include/bpfilter/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ enum bf_matcher_type
BF_MATCHER_IP6_DNET,
/// Matches IPv6 next header
BF_MATCHER_IP6_NEXTHDR,
/// Matches against the IPv6 Differentiated Services Code Point (DSCP) field
BF_MATCHER_IP6_DSCP,
/// Matches against the TCP source port. Stored as big-endian.
BF_MATCHER_TCP_SPORT,
/// Matches against the TCP destination port. Stored as big-endian.
Expand Down
15 changes: 15 additions & 0 deletions src/libbpfilter/matcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,20 @@ static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
_bf_parse_l4_proto, _bf_print_l4_proto),
},
},
[BF_MATCHER_IP6_DSCP] =
{
.layer = BF_MATCHER_LAYER_3,
.hdr_id = ETH_P_IPV6,
.hdr_payload_size = sizeof(uint8_t),
.hdr_payload_offset = 0,
.ops =
{
BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
_bf_parse_u8, _bf_print_u8),
BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
_bf_parse_u8, _bf_print_u8),
},
},
[BF_MATCHER_TCP_SPORT] =
{
.layer = BF_MATCHER_LAYER_4,
Expand Down Expand Up @@ -1461,6 +1475,7 @@ static const char *_bf_matcher_type_strs[] = {
[BF_MATCHER_IP6_DADDR] = "ip6.daddr",
[BF_MATCHER_IP6_DNET] = "ip6.dnet",
[BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
[BF_MATCHER_IP6_DSCP] = "ip6.dscp",
[BF_MATCHER_TCP_SPORT] = "tcp.sport",
[BF_MATCHER_TCP_DPORT] = "tcp.dport",
[BF_MATCHER_TCP_FLAGS] = "tcp.flags",
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ bf_add_e2e_test(e2e matchers/ip4_saddr.sh)
bf_add_e2e_test(e2e matchers/ip4_snet.sh)
bf_add_e2e_test(e2e matchers/ip6_daddr.sh)
bf_add_e2e_test(e2e matchers/ip6_dnet.sh)
bf_add_e2e_test(e2e matchers/ip6_dscp.sh)
bf_add_e2e_test(e2e matchers/ip6_nexthdr.sh)
bf_add_e2e_test(e2e matchers/ip6_saddr.sh)
bf_add_e2e_test(e2e matchers/ip6_snet.sh)
Expand Down
40 changes: 40 additions & 0 deletions tests/e2e/matchers/ip6_dscp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file must be added to tests/e2e/CMakeLists.txt.


set -eux
set -o pipefail

. "$(dirname "$0")"/../e2e_test_util.sh

# Test valid decimal values with 'eq' operator
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 0 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 46 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 255 counter DROP"

# Test valid hexadecimal values with 'eq' operator
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 0x00 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 0x2e counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 0xff counter DROP"

# Test invalid values with 'eq' operator (should fail)
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq abc counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq -1 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 256 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq -0x01 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp eq 0x100 counter DROP")

# Test valid decimal values with 'not' operator
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 0 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 46 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 255 counter DROP"

# Test valid hexadecimal values with 'not' operator
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 0x00 counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 0x2e counter DROP"
bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 0xff counter DROP"

# Test invalid values with 'not' operator (should fail)
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not abc counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not -1 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 256 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not -0x01 counter DROP")
(! bfcli ruleset set --dry-run --from-str "chain xdp BF_HOOK_XDP ACCEPT rule ip6.dscp not 0x100 counter DROP")
89 changes: 89 additions & 0 deletions tests/unit/libbpfilter/matcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,93 @@ static void icmpv6_code(void **state)
bf_matcher_dump(matcher, &prefix);
}

static void ip6_dscp(void **state)
{
_free_bf_matcher_ struct bf_matcher *matcher = NULL;
const struct bf_matcher_ops *ops;
prefix_t prefix = {};

(void)state;

// Test IPv6 DSCP with decimal value 0 (minimum)
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "0"));
assert_non_null(matcher);
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 0);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test with decimal value 255 (maximum)
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "255"));
assert_non_null(matcher);
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 255);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test with different DSCP value (e.g., 46 for EF)
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "46"));
assert_non_null(matcher);
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 46);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test with NE operator
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_NE, "8"));
assert_non_null(matcher);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test with hexadecimal value (0x2e = 46)
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "0x2e"));
assert_non_null(matcher);
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 46);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test with another hexadecimal value (0xff = 255)
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "0xff"));
assert_non_null(matcher);
assert_int_equal(*(uint8_t *)bf_matcher_payload(matcher), 255);
bf_matcher_dump(matcher, &prefix);
bf_matcher_free(&matcher);

// Test print function via ops
assert_ok(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "0x20"));
ops = bf_matcher_get_ops(BF_MATCHER_IP6_DSCP, BF_MATCHER_EQ);
assert_non_null(ops);
assert_non_null(ops->print);
ops->print(bf_matcher_payload(matcher));
}

static void ip6_dscp_invalid(void **state)
{
_free_bf_matcher_ struct bf_matcher *matcher = NULL;

(void)state;

// Test with value > 255
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "256"));

// Test with invalid string
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "not_a_number"));

// Test with negative value
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "-1"));

// Test with value > 0xff in hex
assert_err(bf_matcher_new_from_raw(&matcher, BF_MATCHER_IP6_DSCP,
BF_MATCHER_EQ, "0x100"));
}

static void icmpv6_type(void **state)
{
_free_bf_matcher_ struct bf_matcher *matcher = NULL;
Expand Down Expand Up @@ -1450,6 +1537,8 @@ int main(void)
cmocka_unit_test(ipv6_network_invalid),
cmocka_unit_test(icmp_code),
cmocka_unit_test(icmpv6_code),
cmocka_unit_test(ip6_dscp),
cmocka_unit_test(ip6_dscp_invalid),
cmocka_unit_test(icmpv6_type),
cmocka_unit_test(tcp_port_range),
cmocka_unit_test(udp_port_range),
Expand Down