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
425eabddaf ("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>
This commit is contained in:
Paolo Abeni 2026-07-23 12:46:20 +02:00
commit c2de9edf4f
2 changed files with 51 additions and 12 deletions

View File

@ -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;
ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L4_ADDR, &value);
if (ret)
return ret;
if (sa) {
value = FIELD_PREP(XGMAC_L4SP0, match);
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
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);

View File

@ -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;
}