mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
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:
commit
c2de9edf4f
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user