Skip to content

Commit 97417f6

Browse files
Eli BritsteinSaeed Mahameed
authored andcommitted
net/mlx5e: Fix GRE key by controlling port tunnel entropy calculation
Flow entropy is calculated on the inner packet headers and used for flow distribution in processing, routing etc. For GRE-type encapsulations the entropy value is placed in the eight LSB of the key field in the GRE header as defined in NVGRE RFC 7637. For UDP based encapsulations the entropy value is placed in the source port of the UDP header. The hardware may support entropy calculation specifically for GRE and for all tunneling protocols. With commit df2ef3b ("net/mlx5e: Add GRE protocol offloading") GRE is offloaded, but the hardware is configured by default to calculate flow entropy so packets transmitted on the wire have a wrong key. To support UDP based tunnels (i.e VXLAN), GRE (i.e. no flow entropy) and NVGRE (i.e. with flow entropy) the hardware behaviour must be controlled by the driver. Ensure port entropy calculation is enabled for offloaded VXLAN tunnels and disable port entropy calculation in the presence of offloaded GRE tunnels by monitoring the presence of entropy enabling tunnels (i.e VXLAN) and entropy disabing tunnels (i.e GRE). Fixes: df2ef3b ("net/mlx5e: Add GRE protocol offloading") Signed-off-by: Eli Britstein <elibr@mellanox.com> Reviewed-by: Oz Shlomo <ozsh@mellanox.com> Reviewed-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
1 parent 0dcaafc commit 97417f6

File tree

7 files changed

+254
-5
lines changed

7 files changed

+254
-5
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
3030
mlx5_core-$(CONFIG_MLX5_EN_ARFS) += en_arfs.o
3131
mlx5_core-$(CONFIG_MLX5_EN_RXNFC) += en_fs_ethtool.o
3232
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
33-
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o
33+
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o
3434

3535
#
3636
# Core extra

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "en_tc.h"
4545
#include "en/tc_tun.h"
4646
#include "fs_core.h"
47+
#include "lib/port_tun.h"
4748

4849
#define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \
4950
max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
@@ -1044,14 +1045,23 @@ static void mlx5e_rep_neigh_entry_destroy(struct mlx5e_priv *priv,
10441045
int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv,
10451046
struct mlx5e_encap_entry *e)
10461047
{
1048+
struct mlx5e_rep_priv *rpriv = priv->ppriv;
1049+
struct mlx5_rep_uplink_priv *uplink_priv = &rpriv->uplink_priv;
1050+
struct mlx5_tun_entropy *tun_entropy = &uplink_priv->tun_entropy;
10471051
struct mlx5e_neigh_hash_entry *nhe;
10481052
int err;
10491053

1054+
err = mlx5_tun_entropy_refcount_inc(tun_entropy, e->reformat_type);
1055+
if (err)
1056+
return err;
10501057
nhe = mlx5e_rep_neigh_entry_lookup(priv, &e->m_neigh);
10511058
if (!nhe) {
10521059
err = mlx5e_rep_neigh_entry_create(priv, e, &nhe);
1053-
if (err)
1060+
if (err) {
1061+
mlx5_tun_entropy_refcount_dec(tun_entropy,
1062+
e->reformat_type);
10541063
return err;
1064+
}
10551065
}
10561066
list_add(&e->encap_list, &nhe->encap_list);
10571067
return 0;
@@ -1060,13 +1070,17 @@ int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv,
10601070
void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv,
10611071
struct mlx5e_encap_entry *e)
10621072
{
1073+
struct mlx5e_rep_priv *rpriv = priv->ppriv;
1074+
struct mlx5_rep_uplink_priv *uplink_priv = &rpriv->uplink_priv;
1075+
struct mlx5_tun_entropy *tun_entropy = &uplink_priv->tun_entropy;
10631076
struct mlx5e_neigh_hash_entry *nhe;
10641077

10651078
list_del(&e->encap_list);
10661079
nhe = mlx5e_rep_neigh_entry_lookup(priv, &e->m_neigh);
10671080

10681081
if (list_empty(&nhe->encap_list))
10691082
mlx5e_rep_neigh_entry_destroy(priv, nhe);
1083+
mlx5_tun_entropy_refcount_dec(tun_entropy, e->reformat_type);
10701084
}
10711085

10721086
static int mlx5e_vf_rep_open(struct net_device *dev)
@@ -1564,6 +1578,8 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
15641578
if (err)
15651579
goto destroy_tises;
15661580

1581+
mlx5_init_port_tun_entropy(&uplink_priv->tun_entropy, priv->mdev);
1582+
15671583
/* init indirect block notifications */
15681584
INIT_LIST_HEAD(&uplink_priv->tc_indr_block_priv_list);
15691585
uplink_priv->netdevice_nb.notifier_call = mlx5e_nic_rep_netdevice_event;

drivers/net/ethernet/mellanox/mlx5/core/en_rep.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/rhashtable.h>
3838
#include "eswitch.h"
3939
#include "en.h"
40+
#include "lib/port_tun.h"
4041

4142
#ifdef CONFIG_MLX5_ESWITCH
4243
struct mlx5e_neigh_update_table {
@@ -71,6 +72,8 @@ struct mlx5_rep_uplink_priv {
7172
*/
7273
struct list_head tc_indr_block_priv_list;
7374
struct notifier_block netdevice_nb;
75+
76+
struct mlx5_tun_entropy tun_entropy;
7477
};
7578

7679
struct mlx5e_rep_priv {
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+
#include <linux/module.h>
5+
#include <linux/mlx5/driver.h>
6+
#include <linux/mlx5/port.h>
7+
#include <linux/mlx5/cmd.h>
8+
#include "mlx5_core.h"
9+
#include "lib/port_tun.h"
10+
11+
struct mlx5_port_tun_entropy_flags {
12+
bool force_supported, force_enabled;
13+
bool calc_supported, calc_enabled;
14+
bool gre_calc_supported, gre_calc_enabled;
15+
};
16+
17+
static void mlx5_query_port_tun_entropy(struct mlx5_core_dev *mdev,
18+
struct mlx5_port_tun_entropy_flags *entropy_flags)
19+
{
20+
u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
21+
/* Default values for FW which do not support MLX5_REG_PCMR */
22+
entropy_flags->force_supported = false;
23+
entropy_flags->calc_supported = false;
24+
entropy_flags->gre_calc_supported = false;
25+
entropy_flags->force_enabled = false;
26+
entropy_flags->calc_enabled = true;
27+
entropy_flags->gre_calc_enabled = true;
28+
29+
if (!MLX5_CAP_GEN(mdev, ports_check))
30+
return;
31+
32+
if (mlx5_query_ports_check(mdev, out, sizeof(out)))
33+
return;
34+
35+
entropy_flags->force_supported = !!(MLX5_GET(pcmr_reg, out, entropy_force_cap));
36+
entropy_flags->calc_supported = !!(MLX5_GET(pcmr_reg, out, entropy_calc_cap));
37+
entropy_flags->gre_calc_supported = !!(MLX5_GET(pcmr_reg, out, entropy_gre_calc_cap));
38+
entropy_flags->force_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_force));
39+
entropy_flags->calc_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_calc));
40+
entropy_flags->gre_calc_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_gre_calc));
41+
}
42+
43+
static int mlx5_set_port_tun_entropy_calc(struct mlx5_core_dev *mdev, u8 enable,
44+
u8 force)
45+
{
46+
u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
47+
int err;
48+
49+
err = mlx5_query_ports_check(mdev, in, sizeof(in));
50+
if (err)
51+
return err;
52+
MLX5_SET(pcmr_reg, in, local_port, 1);
53+
MLX5_SET(pcmr_reg, in, entropy_force, force);
54+
MLX5_SET(pcmr_reg, in, entropy_calc, enable);
55+
return mlx5_set_ports_check(mdev, in, sizeof(in));
56+
}
57+
58+
static int mlx5_set_port_gre_tun_entropy_calc(struct mlx5_core_dev *mdev,
59+
u8 enable, u8 force)
60+
{
61+
u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
62+
int err;
63+
64+
err = mlx5_query_ports_check(mdev, in, sizeof(in));
65+
if (err)
66+
return err;
67+
MLX5_SET(pcmr_reg, in, local_port, 1);
68+
MLX5_SET(pcmr_reg, in, entropy_force, force);
69+
MLX5_SET(pcmr_reg, in, entropy_gre_calc, enable);
70+
return mlx5_set_ports_check(mdev, in, sizeof(in));
71+
}
72+
73+
void mlx5_init_port_tun_entropy(struct mlx5_tun_entropy *tun_entropy,
74+
struct mlx5_core_dev *mdev)
75+
{
76+
struct mlx5_port_tun_entropy_flags entropy_flags;
77+
78+
tun_entropy->mdev = mdev;
79+
mutex_init(&tun_entropy->lock);
80+
mlx5_query_port_tun_entropy(mdev, &entropy_flags);
81+
tun_entropy->num_enabling_entries = 0;
82+
tun_entropy->num_disabling_entries = 0;
83+
tun_entropy->enabled = entropy_flags.calc_enabled;
84+
tun_entropy->enabled =
85+
(entropy_flags.calc_supported) ?
86+
entropy_flags.calc_enabled : true;
87+
}
88+
89+
static int mlx5_set_entropy(struct mlx5_tun_entropy *tun_entropy,
90+
int reformat_type, bool enable)
91+
{
92+
struct mlx5_port_tun_entropy_flags entropy_flags;
93+
int err;
94+
95+
mlx5_query_port_tun_entropy(tun_entropy->mdev, &entropy_flags);
96+
/* Tunnel entropy calculation may be controlled either on port basis
97+
* for all tunneling protocols or specifically for GRE protocol.
98+
* Prioritize GRE protocol control (if capable) over global port
99+
* configuration.
100+
*/
101+
if (entropy_flags.gre_calc_supported &&
102+
reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) {
103+
/* Other applications may change the global FW entropy
104+
* calculations settings. Check that the current entropy value
105+
* is the negative of the updated value.
106+
*/
107+
if (entropy_flags.force_enabled &&
108+
enable == entropy_flags.gre_calc_enabled) {
109+
mlx5_core_warn(tun_entropy->mdev,
110+
"Unexpected GRE entropy calc setting - expected %d",
111+
!entropy_flags.gre_calc_enabled);
112+
return -EOPNOTSUPP;
113+
}
114+
err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, enable,
115+
entropy_flags.force_supported);
116+
if (err)
117+
return err;
118+
/* if we turn on the entropy we don't need to force it anymore */
119+
if (entropy_flags.force_supported && enable) {
120+
err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, 1, 0);
121+
if (err)
122+
return err;
123+
}
124+
} else if (entropy_flags.calc_supported) {
125+
/* Other applications may change the global FW entropy
126+
* calculations settings. Check that the current entropy value
127+
* is the negative of the updated value.
128+
*/
129+
if (entropy_flags.force_enabled &&
130+
enable == entropy_flags.calc_enabled) {
131+
mlx5_core_warn(tun_entropy->mdev,
132+
"Unexpected entropy calc setting - expected %d",
133+
!entropy_flags.calc_enabled);
134+
return -EOPNOTSUPP;
135+
}
136+
/* GRE requires disabling entropy calculation. if there are
137+
* enabling entries (i.e VXLAN) we cannot turn it off for them,
138+
* thus fail.
139+
*/
140+
if (tun_entropy->num_enabling_entries)
141+
return -EOPNOTSUPP;
142+
err = mlx5_set_port_tun_entropy_calc(tun_entropy->mdev, enable,
143+
entropy_flags.force_supported);
144+
if (err)
145+
return err;
146+
tun_entropy->enabled = enable;
147+
/* if we turn on the entropy we don't need to force it anymore */
148+
if (entropy_flags.force_supported && enable) {
149+
err = mlx5_set_port_tun_entropy_calc(tun_entropy->mdev, 1, 0);
150+
if (err)
151+
return err;
152+
}
153+
}
154+
155+
return 0;
156+
}
157+
158+
/* the function manages the refcount for enabling/disabling tunnel types.
159+
* the return value indicates if the inc is successful or not, depending on
160+
* entropy capabilities and configuration.
161+
*/
162+
int mlx5_tun_entropy_refcount_inc(struct mlx5_tun_entropy *tun_entropy,
163+
int reformat_type)
164+
{
165+
/* the default is error for unknown (non VXLAN/GRE tunnel types) */
166+
int err = -EOPNOTSUPP;
167+
168+
mutex_lock(&tun_entropy->lock);
169+
if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN &&
170+
tun_entropy->enabled) {
171+
/* in case entropy calculation is enabled for all tunneling
172+
* types, it is ok for VXLAN, so approve.
173+
* otherwise keep the error default.
174+
*/
175+
tun_entropy->num_enabling_entries++;
176+
err = 0;
177+
} else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) {
178+
/* turn off the entropy only for the first GRE rule.
179+
* for the next rules the entropy was already disabled
180+
* successfully.
181+
*/
182+
if (tun_entropy->num_disabling_entries == 0)
183+
err = mlx5_set_entropy(tun_entropy, reformat_type, 0);
184+
else
185+
err = 0;
186+
if (!err)
187+
tun_entropy->num_disabling_entries++;
188+
}
189+
mutex_unlock(&tun_entropy->lock);
190+
191+
return err;
192+
}
193+
194+
void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy,
195+
int reformat_type)
196+
{
197+
mutex_lock(&tun_entropy->lock);
198+
if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN)
199+
tun_entropy->num_enabling_entries--;
200+
else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE &&
201+
--tun_entropy->num_disabling_entries == 0)
202+
mlx5_set_entropy(tun_entropy, reformat_type, 1);
203+
mutex_unlock(&tun_entropy->lock);
204+
}
205+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+
#ifndef __MLX5_PORT_TUN_H__
5+
#define __MLX5_PORT_TUN_H__
6+
7+
#include <linux/mlx5/driver.h>
8+
9+
struct mlx5_tun_entropy {
10+
struct mlx5_core_dev *mdev;
11+
u32 num_enabling_entries;
12+
u32 num_disabling_entries;
13+
u8 enabled;
14+
struct mutex lock; /* lock the entropy fields */
15+
};
16+
17+
void mlx5_init_port_tun_entropy(struct mlx5_tun_entropy *tun_entropy,
18+
struct mlx5_core_dev *mdev);
19+
int mlx5_tun_entropy_refcount_inc(struct mlx5_tun_entropy *tun_entropy,
20+
int reformat_type);
21+
void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy,
22+
int reformat_type);
23+
24+
#endif /* __MLX5_PORT_TUN_H__ */

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,8 +764,7 @@ int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
764764
}
765765
EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
766766

767-
static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out,
768-
int outlen)
767+
int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
769768
{
770769
u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
771770

@@ -774,7 +773,7 @@ static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out,
774773
outlen, MLX5_REG_PCMR, 0, 0);
775774
}
776775

777-
static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
776+
int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
778777
{
779778
u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
780779

include/linux/mlx5/port.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
182182
int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode);
183183
int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode);
184184

185+
int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen);
186+
int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen);
185187
int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable);
186188
void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
187189
bool *enabled);

0 commit comments

Comments
 (0)