Skip to content

Commit b6dfff2

Browse files
Paul BlakeySaeed Mahameed
authored andcommitted
net/mlx5e: Fix matching on modified inner ip_ecn bits
Tunnel device follows RFC 6040, and during decapsulation inner ip_ecn might change depending on inner and outer ip_ecn as follows: +---------+----------------------------------------+ |Arriving | Arriving Outer Header | | Inner +---------+---------+---------+----------+ | Header | Not-ECT | ECT(0) | ECT(1) | CE | +---------+---------+---------+---------+----------+ | Not-ECT | Not-ECT | Not-ECT | Not-ECT | <drop> | | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE* | | ECT(1) | ECT(1) | ECT(1) | ECT(1)* | CE* | | CE | CE | CE | CE | CE | +---------+---------+---------+---------+----------+ Cells marked above are changed from original inner packet ip_ecn value. Tc then matches on the modified inner ip_ecn, but hw offload which matches the inner ip_ecn value before decap, will fail. Fix that by mapping all the cases of outer and inner ip_ecn matching, and only supporting cases where we know inner wouldn't be changed by decap, or in the outer ip_ecn=CE case, inner ip_ecn didn't matter. Fixes: bcef735 ("net/mlx5e: Offload TC matching on tos/ttl for ip tunnels") Signed-off-by: Paul Blakey <[email protected]> Reviewed-by: Oz Shlomo <[email protected]> Reviewed-by: Eli Cohen <[email protected]> Reviewed-by: Roi Dayan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 01c3fd1 commit b6dfff2

File tree

1 file changed

+116
-4
lines changed
  • drivers/net/ethernet/mellanox/mlx5/core

1 file changed

+116
-4
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,111 @@ u8 mlx5e_tc_get_ip_version(struct mlx5_flow_spec *spec, bool outer)
19491949
return ip_version;
19501950
}
19511951

1952+
/* Tunnel device follows RFC 6040, see include/net/inet_ecn.h.
1953+
* And changes inner ip_ecn depending on inner and outer ip_ecn as follows:
1954+
* +---------+----------------------------------------+
1955+
* |Arriving | Arriving Outer Header |
1956+
* | Inner +---------+---------+---------+----------+
1957+
* | Header | Not-ECT | ECT(0) | ECT(1) | CE |
1958+
* +---------+---------+---------+---------+----------+
1959+
* | Not-ECT | Not-ECT | Not-ECT | Not-ECT | <drop> |
1960+
* | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE* |
1961+
* | ECT(1) | ECT(1) | ECT(1) | ECT(1)* | CE* |
1962+
* | CE | CE | CE | CE | CE |
1963+
* +---------+---------+---------+---------+----------+
1964+
*
1965+
* Tc matches on inner after decapsulation on tunnel device, but hw offload matches
1966+
* the inner ip_ecn value before hardware decap action.
1967+
*
1968+
* Cells marked are changed from original inner packet ip_ecn value during decap, and
1969+
* so matching those values on inner ip_ecn before decap will fail.
1970+
*
1971+
* The following helper allows offload when inner ip_ecn won't be changed by outer ip_ecn,
1972+
* except for the outer ip_ecn = CE, where in all cases inner ip_ecn will be changed to CE,
1973+
* and such we can drop the inner ip_ecn=CE match.
1974+
*/
1975+
1976+
static int mlx5e_tc_verify_tunnel_ecn(struct mlx5e_priv *priv,
1977+
struct flow_cls_offload *f,
1978+
bool *match_inner_ecn)
1979+
{
1980+
u8 outer_ecn_mask = 0, outer_ecn_key = 0, inner_ecn_mask = 0, inner_ecn_key = 0;
1981+
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
1982+
struct netlink_ext_ack *extack = f->common.extack;
1983+
struct flow_match_ip match;
1984+
1985+
*match_inner_ecn = true;
1986+
1987+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
1988+
flow_rule_match_enc_ip(rule, &match);
1989+
outer_ecn_key = match.key->tos & INET_ECN_MASK;
1990+
outer_ecn_mask = match.mask->tos & INET_ECN_MASK;
1991+
}
1992+
1993+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
1994+
flow_rule_match_ip(rule, &match);
1995+
inner_ecn_key = match.key->tos & INET_ECN_MASK;
1996+
inner_ecn_mask = match.mask->tos & INET_ECN_MASK;
1997+
}
1998+
1999+
if (outer_ecn_mask != 0 && outer_ecn_mask != INET_ECN_MASK) {
2000+
NL_SET_ERR_MSG_MOD(extack, "Partial match on enc_tos ecn bits isn't supported");
2001+
netdev_warn(priv->netdev, "Partial match on enc_tos ecn bits isn't supported");
2002+
return -EOPNOTSUPP;
2003+
}
2004+
2005+
if (!outer_ecn_mask) {
2006+
if (!inner_ecn_mask)
2007+
return 0;
2008+
2009+
NL_SET_ERR_MSG_MOD(extack,
2010+
"Matching on tos ecn bits without also matching enc_tos ecn bits isn't supported");
2011+
netdev_warn(priv->netdev,
2012+
"Matching on tos ecn bits without also matching enc_tos ecn bits isn't supported");
2013+
return -EOPNOTSUPP;
2014+
}
2015+
2016+
if (inner_ecn_mask && inner_ecn_mask != INET_ECN_MASK) {
2017+
NL_SET_ERR_MSG_MOD(extack,
2018+
"Partial match on tos ecn bits with match on enc_tos ecn bits isn't supported");
2019+
netdev_warn(priv->netdev,
2020+
"Partial match on tos ecn bits with match on enc_tos ecn bits isn't supported");
2021+
return -EOPNOTSUPP;
2022+
}
2023+
2024+
if (!inner_ecn_mask)
2025+
return 0;
2026+
2027+
/* Both inner and outer have full mask on ecn */
2028+
2029+
if (outer_ecn_key == INET_ECN_ECT_1) {
2030+
/* inner ecn might change by DECAP action */
2031+
2032+
NL_SET_ERR_MSG_MOD(extack, "Match on enc_tos ecn = ECT(1) isn't supported");
2033+
netdev_warn(priv->netdev, "Match on enc_tos ecn = ECT(1) isn't supported");
2034+
return -EOPNOTSUPP;
2035+
}
2036+
2037+
if (outer_ecn_key != INET_ECN_CE)
2038+
return 0;
2039+
2040+
if (inner_ecn_key != INET_ECN_CE) {
2041+
/* Can't happen in software, as packet ecn will be changed to CE after decap */
2042+
NL_SET_ERR_MSG_MOD(extack,
2043+
"Match on tos enc_tos ecn = CE while match on tos ecn != CE isn't supported");
2044+
netdev_warn(priv->netdev,
2045+
"Match on tos enc_tos ecn = CE while match on tos ecn != CE isn't supported");
2046+
return -EOPNOTSUPP;
2047+
}
2048+
2049+
/* outer ecn = CE, inner ecn = CE, as decap will change inner ecn to CE in anycase,
2050+
* drop match on inner ecn
2051+
*/
2052+
*match_inner_ecn = false;
2053+
2054+
return 0;
2055+
}
2056+
19522057
static int parse_tunnel_attr(struct mlx5e_priv *priv,
19532058
struct mlx5e_tc_flow *flow,
19542059
struct mlx5_flow_spec *spec,
@@ -2144,6 +2249,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
21442249
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
21452250
struct flow_dissector *dissector = rule->match.dissector;
21462251
enum fs_flow_table_type fs_type;
2252+
bool match_inner_ecn = true;
21472253
u16 addr_type = 0;
21482254
u8 ip_proto = 0;
21492255
u8 *match_level;
@@ -2197,6 +2303,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
21972303
headers_c = get_match_inner_headers_criteria(spec);
21982304
headers_v = get_match_inner_headers_value(spec);
21992305
}
2306+
2307+
err = mlx5e_tc_verify_tunnel_ecn(priv, f, &match_inner_ecn);
2308+
if (err)
2309+
return err;
22002310
}
22012311

22022312
err = mlx5e_flower_parse_meta(filter_dev, f);
@@ -2420,10 +2530,12 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
24202530
struct flow_match_ip match;
24212531

24222532
flow_rule_match_ip(rule, &match);
2423-
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn,
2424-
match.mask->tos & 0x3);
2425-
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn,
2426-
match.key->tos & 0x3);
2533+
if (match_inner_ecn) {
2534+
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn,
2535+
match.mask->tos & 0x3);
2536+
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn,
2537+
match.key->tos & 0x3);
2538+
}
24272539

24282540
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp,
24292541
match.mask->tos >> 2);

0 commit comments

Comments
 (0)