-
Notifications
You must be signed in to change notification settings - Fork 52
lib: chain: disable rules with incompatible same-layer matchers #471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||
| #!/usr/bin/env bash | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the e2e tests valuable here? IIUC, the prior behavior would be the same as the behavior after the change, so what are we really testing? The only difference would be the codegen should be omitted and the rule should be disabled, which the e2e tests can't really cover, right? |
||||
|
|
||||
| # Rules with matchers on the same layer but different protocols (e.g. ip4 + ip6) | ||||
| # should be disabled: the chain loads successfully but the rule has no effect. | ||||
|
|
||||
| . "$(dirname "$0")"/../e2e_test_util.sh | ||||
|
|
||||
| make_sandbox | ||||
| start_bpfilter | ||||
|
|
||||
| # Baseline: ping works before any chain is loaded. | ||||
| ping -c 1 -W 0.1 ${NS_IP_ADDR} | ||||
|
|
||||
| # L3 conflict: ip4.saddr + ip6.daddr in the same rule. The rule can never match | ||||
| # a packet (IPv4 and IPv6 are mutually exclusive), so it should be disabled. | ||||
| ${FROM_NS} bfcli chain set --from-str "chain xdp BF_HOOK_XDP{ifindex=${NS_IFINDEX}} ACCEPT rule ip4.saddr eq ${HOST_IP_ADDR} ip6.daddr eq ::1 counter DROP" | ||||
|
|
||||
| # Ping must still succeed: the DROP rule is disabled, default policy is ACCEPT. | ||||
| ping -c 1 -W 0.1 ${NS_IP_ADDR} | ||||
|
|
||||
| # L4 conflict: tcp.sport + udp.dport in the same rule. | ||||
| ${FROM_NS} bfcli chain set --from-str "chain xdp BF_HOOK_XDP{ifindex=${NS_IFINDEX}} ACCEPT rule tcp.sport eq 80 udp.dport eq 53 counter DROP" | ||||
|
|
||||
| ping -c 1 -W 0.1 ${NS_IP_ADDR} | ||||
|
|
||||
| stop_bpfilter | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude: Explicit
Suggested change
|
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -141,6 +141,137 @@ static void mixed_enabled_disabled_log_flag(void **state) | |
| assert_int_equal(chain->flags & BF_FLAG(BF_CHAIN_LOG), 0); | ||
| } | ||
|
|
||
| static void incompatible_matchers_disable_rule(void **state) | ||
| { | ||
| (void)state; | ||
|
|
||
| // L3 conflict: IPv4 + IPv6 matchers. | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint32_t ip4_addr = 0; | ||
| uint8_t ip6_addr[16] = {}; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_IP4_SADDR, BF_MATCHER_EQ, | ||
| &ip4_addr, sizeof(ip4_addr))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_IP6_DADDR, BF_MATCHER_EQ, | ||
| ip6_addr, sizeof(ip6_addr))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_true(rule->disabled); | ||
| } | ||
|
|
||
| // L4 conflict: TCP + UDP matchers. | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint16_t port = 0; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_TCP_SPORT, BF_MATCHER_EQ, | ||
| &port, sizeof(port))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_UDP_DPORT, BF_MATCHER_EQ, | ||
| &port, sizeof(port))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_true(rule->disabled); | ||
| } | ||
|
|
||
| // L4 conflict: ICMP + ICMPv6 matchers. | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint8_t type_val = 0; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_ICMP_TYPE, BF_MATCHER_EQ, | ||
| &type_val, sizeof(type_val))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_ICMPV6_TYPE, | ||
| BF_MATCHER_EQ, &type_val, | ||
| sizeof(type_val))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_true(rule->disabled); | ||
| } | ||
|
|
||
| // No conflict: same protocol at same layer (TCP sport + TCP dport). | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint16_t port = 0; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_TCP_SPORT, BF_MATCHER_EQ, | ||
| &port, sizeof(port))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_TCP_DPORT, BF_MATCHER_EQ, | ||
| &port, sizeof(port))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_false(rule->disabled); | ||
| } | ||
|
|
||
| // No conflict: different layers (IPv4 + TCP). | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint32_t ip4_addr = 0; | ||
| uint16_t port = 0; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_IP4_SADDR, BF_MATCHER_EQ, | ||
| &ip4_addr, sizeof(ip4_addr))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_TCP_SPORT, BF_MATCHER_EQ, | ||
| &port, sizeof(port))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_false(rule->disabled); | ||
| } | ||
|
|
||
| // Disabled rule does not set BF_CHAIN_LOG. | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = NULL; | ||
| _clean_bf_list_ bf_list rules = | ||
| bf_list_default(bf_rule_free, bf_rule_pack); | ||
| struct bf_rule *rule = NULL; | ||
| uint32_t ip4_addr = 0; | ||
| uint8_t ip6_addr[16] = {}; | ||
|
|
||
| assert_ok(bf_rule_new(&rule)); | ||
| rule->log = 1; | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_IP4_SADDR, BF_MATCHER_EQ, | ||
| &ip4_addr, sizeof(ip4_addr))); | ||
| assert_ok(bf_rule_add_matcher(rule, BF_MATCHER_IP6_DADDR, BF_MATCHER_EQ, | ||
| ip6_addr, sizeof(ip6_addr))); | ||
| assert_ok(bf_list_add_tail(&rules, rule)); | ||
|
|
||
| assert_ok(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, | ||
| BF_VERDICT_ACCEPT, NULL, &rules)); | ||
| assert_true(rule->disabled); | ||
| assert_int_equal(chain->flags & BF_FLAG(BF_CHAIN_LOG), 0); | ||
| } | ||
| } | ||
|
|
||
| static void get_set_by_name(void **state) | ||
| { | ||
| _free_bf_chain_ struct bf_chain *chain = bft_chain_dummy(true); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude: The test covers L3/L4 conflicts and non-conflict cases well. Consider adding sub-cases for a couple of boundary inputs to
|
||
|
|
@@ -159,6 +290,7 @@ int main(void) | |
| cmocka_unit_test(dump), | ||
| cmocka_unit_test(get_set_from_matcher), | ||
| cmocka_unit_test(mixed_enabled_disabled_log_flag), | ||
| cmocka_unit_test(incompatible_matchers_disable_rule), | ||
| cmocka_unit_test(get_set_by_name), | ||
| }; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rule->disabled = r | _bf_rule_has_incompatible_matchers(rule);? Or probably||so we don't run_bf_rule_has_incompatible_matchers(rule)unless we need to