aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-07-23 12:46:20 +0200
committerPaolo Abeni <pabeni@redhat.com>2026-07-23 12:46:20 +0200
commitc2de9edf4f7027d669fd7a95964353e2c0c46bbd (patch)
tree678a2776f46a88dda93a0d44ef5fb1b4b9620cb8
parent980a813452754f8001704744e92f7aa697c53dd3 (diff)
parenta448f821289934b961dd9d8d0beb006cc8937ba2 (diff)
Merge branch 'net-stmmac-l3-l4-filter-bug-fixes'
Nazim Amirul says: ==================== net: stmmac: L3/L4 filter bug fixes This series fixes three bugs in the stmmac L3/L4 TC flower filter implementation for the XGMAC2 core. All three patches target net. The L3/L4 filter match count statistics patch (originally patch 4/4) has been split out and will be sent separately against net-next per Andrew Lunn's review of v1. Patch 1 fixes a register corruption bug in the L4 filter port configuration. The XGMAC_L4_ADDR register holds both source and destination port match values in a single register. The original code overwrites the entire register when setting either field, silently erasing the other. This is fixed by using a read-modify-write sequence. Patch 2 fixes the basic flow match parser to properly reject unsupported offload requests with -EOPNOTSUPP instead of silently accepting them. Unsupported cases include partial protocol masks, non-IPv4 network proto, and non-TCP/UDP transport proto. Extack messages are now included so users know exactly which part of the match is unsupported. The -EOPNOTSUPP is also now returned directly instead of using break, which was silently discarding the error on FLOW_CLS_REPLACE operations. Patch 3 fixes a stale action bug on filter deletion. When a filter entry with a drop action is deleted, the action field was not reset, causing it to persist and potentially affect subsequent filter configurations. All three patches fix the original L3/L4 filter implementation introduced in 425eabddaf0f ("net: stmmac: Implement L3/L4 Filters using TC Flower"). ==================== Link: https://patch.msgid.link/20260714023716.29865-1-muhammad.nazim.amirul.nazle.asmade@altera.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c28
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c35
2 files changed, 51 insertions, 12 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index f02b434bbd50..52054f31376d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -1370,36 +1370,40 @@ static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
value &= ~XGMAC_L4PEN0;
}
- value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0);
- value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0);
if (sa) {
value |= XGMAC_L4SPM0;
if (inv)
value |= XGMAC_L4SPIM0;
+ else
+ value &= ~XGMAC_L4SPIM0;
} else {
value |= XGMAC_L4DPM0;
if (inv)
value |= XGMAC_L4DPIM0;
+ else
+ value &= ~XGMAC_L4DPIM0;
}
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
if (ret)
return ret;
- if (sa) {
- value = FIELD_PREP(XGMAC_L4SP0, match);
+ ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L4_ADDR, &value);
+ if (ret)
+ return ret;
- ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
- if (ret)
- return ret;
+ if (sa) {
+ value &= ~XGMAC_L4SP0;
+ value |= FIELD_PREP(XGMAC_L4SP0, match);
} else {
- value = FIELD_PREP(XGMAC_L4DP0, match);
-
- ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
- if (ret)
- return ret;
+ value &= ~XGMAC_L4DP0;
+ value |= FIELD_PREP(XGMAC_L4DP0, match);
}
+ ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
+ if (ret)
+ return ret;
+
if (!en)
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index d78652718599..14cabe76e53e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -446,6 +446,7 @@ static int tc_parse_flow_actions(struct stmmac_priv *priv,
}
#define ETHER_TYPE_FULL_MASK cpu_to_be16(~0)
+#define IP_PROTO_FULL_MASK 0xFF
static int tc_add_basic_flow(struct stmmac_priv *priv,
struct flow_cls_offload *cls,
@@ -461,6 +462,37 @@ static int tc_add_basic_flow(struct stmmac_priv *priv,
flow_rule_match_basic(rule, &match);
+ /* Both network proto and transport proto not present in the key */
+ if (!match.mask || !(match.mask->n_proto || match.mask->ip_proto)) {
+ NL_SET_ERR_MSG_MOD(cls->common.extack,
+ "filter must specify network or transport protocol");
+ return -EOPNOTSUPP;
+ }
+
+ /* If the proto is present in the key and is not full mask */
+ if ((match.mask->n_proto && match.mask->n_proto != ETHER_TYPE_FULL_MASK) ||
+ (match.mask->ip_proto && match.mask->ip_proto != IP_PROTO_FULL_MASK)) {
+ NL_SET_ERR_MSG_MOD(cls->common.extack,
+ "only full protocol mask is supported");
+ return -EOPNOTSUPP;
+ }
+
+ /* Network proto is present in the key and is not IPv4 */
+ if (match.mask->n_proto && match.key->n_proto != cpu_to_be16(ETH_P_IP)) {
+ NL_SET_ERR_MSG_MOD(cls->common.extack,
+ "only IPv4 network protocol is supported");
+ return -EOPNOTSUPP;
+ }
+
+ /* Transport proto is present in the key and is not TCP or UDP */
+ if (match.mask->ip_proto &&
+ match.key->ip_proto != IPPROTO_TCP &&
+ match.key->ip_proto != IPPROTO_UDP) {
+ NL_SET_ERR_MSG_MOD(cls->common.extack,
+ "only TCP and UDP transport protocols are supported");
+ return -EOPNOTSUPP;
+ }
+
entry->ip_proto = match.key->ip_proto;
return 0;
}
@@ -598,6 +630,8 @@ static int tc_add_flow(struct stmmac_priv *priv,
ret = tc_flow_parsers[i].fn(priv, cls, entry);
if (!ret)
entry->in_use = true;
+ else if (ret == -EOPNOTSUPP)
+ return ret;
}
if (!entry->in_use)
@@ -627,6 +661,7 @@ static int tc_del_flow(struct stmmac_priv *priv,
entry->in_use = false;
entry->cookie = 0;
entry->is_l4 = false;
+ entry->action = 0;
return ret;
}