Skip to content

Commit abef849

Browse files
committed
Merge branch 'mlxsw-handle-mtu-values'
Petr Machata says: ==================== mlxsw: Handle MTU values Amit Cohen writes: The driver uses two values for maximum MTU, but neither is accurate. In addition, the value which is configured to hardware is not calculated correctly. Handle these issues and expose accurate values for minimum and maximum MTU per netdevice. Add test cases to check that the exposed values are really supported. Patch set overview: Patches #1-#3 set the driver to use accurate values for MTU Patch #4 aligns the driver to always use the same value for maximum MTU Patch #5 adds a test ==================== Link: https://lore.kernel.org/r/cover.1718275854.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents afc5625 + 4be3dcc commit abef849

6 files changed

Lines changed: 295 additions & 32 deletions

File tree

drivers/net/ethernet/mellanox/mlxsw/port.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
#include <linux/types.h>
88

9-
#define MLXSW_PORT_MAX_MTU 10000
9+
#define MLXSW_PORT_MAX_MTU (10 * 1024)
10+
#define MLXSW_PORT_ETH_FRAME_HDR (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
1011

1112
#define MLXSW_PORT_DEFAULT_VID 1
1213

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -405,29 +405,12 @@ static int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port)
405405
mlxsw_sp_port->dev->dev_addr);
406406
}
407407

408-
static int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu)
409-
{
410-
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
411-
char pmtu_pl[MLXSW_REG_PMTU_LEN];
412-
int err;
413-
414-
mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0);
415-
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
416-
if (err)
417-
return err;
418-
419-
*p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
420-
return 0;
421-
}
422-
423408
static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
424409
{
425410
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
426411
char pmtu_pl[MLXSW_REG_PMTU_LEN];
427412

428-
mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
429-
if (mtu > mlxsw_sp_port->max_mtu)
430-
return -EINVAL;
413+
mtu += MLXSW_PORT_ETH_FRAME_HDR;
431414

432415
mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu);
433416
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
@@ -1697,8 +1680,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,
16971680
NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
16981681
dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;
16991682

1700-
dev->min_mtu = 0;
1701-
dev->max_mtu = ETH_MAX_MTU;
1683+
dev->min_mtu = ETH_MIN_MTU;
1684+
dev->max_mtu = MLXSW_PORT_MAX_MTU - MLXSW_PORT_ETH_FRAME_HDR;
17021685

17031686
/* Each packet needs to have a Tx header (metadata) on top all other
17041687
* headers.
@@ -1727,13 +1710,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,
17271710
goto err_max_speed_get;
17281711
}
17291712

1730-
err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu);
1731-
if (err) {
1732-
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n",
1733-
mlxsw_sp_port->local_port);
1734-
goto err_port_max_mtu_get;
1735-
}
1736-
17371713
err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);
17381714
if (err) {
17391715
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",
@@ -1877,7 +1853,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,
18771853
err_port_buffers_init:
18781854
err_port_admin_status_set:
18791855
err_port_mtu_set:
1880-
err_port_max_mtu_get:
18811856
err_max_speed_get:
18821857
err_port_speed_by_width_set:
18831858
err_port_system_port_mapping_set:

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ struct mlxsw_sp_port {
359359
u16 egr_types;
360360
struct mlxsw_sp_ptp_port_stats stats;
361361
} ptp;
362-
int max_mtu;
363362
u32 max_speed;
364363
struct mlxsw_sp_hdroom *hdroom;
365364
u64 module_overheat_initial_val;

drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,13 @@ void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
399399
struct mlxsw_sp_hdroom *hdroom)
400400
{
401401
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
402+
unsigned int max_mtu = mlxsw_sp_port->dev->max_mtu;
402403
u16 reserve_cells;
403404
int i;
404405

406+
max_mtu += MLXSW_PORT_ETH_FRAME_HDR;
405407
/* Internal buffer. */
406-
reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_mtu,
408+
reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, max_mtu,
407409
mlxsw_sp_port->max_speed);
408410
reserve_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, reserve_cells);
409411
hdroom->int_buf.reserve_cells = reserve_cells;
@@ -613,7 +615,9 @@ static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
613615
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
614616

615617
/* Buffer 9 is used for control traffic. */
616-
size9 = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, mlxsw_sp_port->max_mtu);
618+
size9 = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port,
619+
mlxsw_sp_port->dev->max_mtu +
620+
MLXSW_PORT_ETH_FRAME_HDR);
617621
hdroom.bufs.buf[9].size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size9);
618622

619623
return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom, true);

tools/testing/selftests/net/forwarding/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ TEST_PROGS = bridge_fdb_learning_limit.sh \
3939
ipip_hier_gre.sh \
4040
lib_sh_test.sh \
4141
local_termination.sh \
42+
min_max_mtu.sh \
4243
mirror_gre_bound.sh \
4344
mirror_gre_bridge_1d.sh \
4445
mirror_gre_bridge_1d_vlan.sh \
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
# +--------------------+
5+
# | H1 |
6+
# | |
7+
# | $h1.10 + |
8+
# | 192.0.2.2/24 | |
9+
# | 2001:db8:1::2/64 | |
10+
# | | |
11+
# | $h1 + |
12+
# | | |
13+
# +------------------|-+
14+
# |
15+
# +------------------|-+
16+
# | SW | |
17+
# | $swp1 + |
18+
# | | |
19+
# | $swp1.10 + |
20+
# | 192.0.2.1/24 |
21+
# | 2001:db8:1::1/64 |
22+
# | |
23+
# +--------------------+
24+
25+
ALL_TESTS="
26+
ping_ipv4
27+
ping_ipv6
28+
max_mtu_config_test
29+
max_mtu_traffic_test
30+
min_mtu_config_test
31+
min_mtu_traffic_test
32+
"
33+
34+
NUM_NETIFS=2
35+
source lib.sh
36+
37+
h1_create()
38+
{
39+
simple_if_init $h1
40+
vlan_create $h1 10 v$h1 192.0.2.2/24 2001:db8:1::2/64
41+
}
42+
43+
h1_destroy()
44+
{
45+
vlan_destroy $h1 10 192.0.2.2/24 2001:db8:1::2/64
46+
simple_if_fini $h1
47+
}
48+
49+
switch_create()
50+
{
51+
ip li set dev $swp1 up
52+
vlan_create $swp1 10 "" 192.0.2.1/24 2001:db8:1::1/64
53+
}
54+
55+
switch_destroy()
56+
{
57+
ip li set dev $swp1 down
58+
vlan_destroy $swp1 10
59+
}
60+
61+
setup_prepare()
62+
{
63+
h1=${NETIFS[p1]}
64+
swp1=${NETIFS[p2]}
65+
66+
vrf_prepare
67+
68+
h1_create
69+
70+
switch_create
71+
72+
forwarding_enable
73+
}
74+
75+
cleanup()
76+
{
77+
pre_cleanup
78+
79+
forwarding_restore
80+
81+
switch_destroy
82+
83+
h1_destroy
84+
85+
vrf_cleanup
86+
}
87+
88+
ping_ipv4()
89+
{
90+
ping_test $h1.10 192.0.2.1
91+
}
92+
93+
ping_ipv6()
94+
{
95+
ping6_test $h1.10 2001:db8:1::1
96+
}
97+
98+
min_max_mtu_get_if()
99+
{
100+
local dev=$1; shift
101+
local min_max=$1; shift
102+
103+
ip -d -j link show $dev | jq ".[].$min_max"
104+
}
105+
106+
ensure_compatible_min_max_mtu()
107+
{
108+
local min_max=$1; shift
109+
110+
local mtu=$(min_max_mtu_get_if ${NETIFS[p1]} $min_max)
111+
local i
112+
113+
for ((i = 2; i <= NUM_NETIFS; ++i)); do
114+
local current_mtu=$(min_max_mtu_get_if ${NETIFS[p$i]} $min_max)
115+
116+
if [ $current_mtu -ne $mtu ]; then
117+
return 1
118+
fi
119+
done
120+
}
121+
122+
mtu_set_if()
123+
{
124+
local dev=$1; shift
125+
local mtu=$1; shift
126+
local should_fail=${1:-0}; shift
127+
128+
mtu_set $dev $mtu 2>/dev/null
129+
check_err_fail $should_fail $? "Set MTU $mtu for $dev"
130+
}
131+
132+
mtu_set_all_if()
133+
{
134+
local mtu=$1; shift
135+
local i
136+
137+
for ((i = 1; i <= NUM_NETIFS; ++i)); do
138+
mtu_set_if ${NETIFS[p$i]} $mtu
139+
mtu_set_if ${NETIFS[p$i]}.10 $mtu
140+
done
141+
}
142+
143+
mtu_restore_all_if()
144+
{
145+
local i
146+
147+
for ((i = 1; i <= NUM_NETIFS; ++i)); do
148+
mtu_restore ${NETIFS[p$i]}.10
149+
mtu_restore ${NETIFS[p$i]}
150+
done
151+
}
152+
153+
mtu_test_ping4()
154+
{
155+
local mtu=$1; shift
156+
local should_fail=$1; shift
157+
158+
# Ping adds 8 bytes for ICMP header and 20 bytes for IP header
159+
local ping_headers_len=$((20 + 8))
160+
local pkt_size=$((mtu - ping_headers_len))
161+
162+
ping_do $h1.10 192.0.2.1 "-s $pkt_size -M do"
163+
check_err_fail $should_fail $? "Ping, packet size: $pkt_size"
164+
}
165+
166+
mtu_test_ping6()
167+
{
168+
local mtu=$1; shift
169+
local should_fail=$1; shift
170+
171+
# Ping adds 8 bytes for ICMP header and 40 bytes for IPv6 header
172+
local ping6_headers_len=$((40 + 8))
173+
local pkt_size=$((mtu - ping6_headers_len))
174+
175+
ping6_do $h1.10 2001:db8:1::1 "-s $pkt_size -M do"
176+
check_err_fail $should_fail $? "Ping6, packet size: $pkt_size"
177+
}
178+
179+
max_mtu_config_test()
180+
{
181+
local i
182+
183+
RET=0
184+
185+
for ((i = 1; i <= NUM_NETIFS; ++i)); do
186+
local dev=${NETIFS[p$i]}
187+
local max_mtu=$(min_max_mtu_get_if $dev "max_mtu")
188+
local should_fail
189+
190+
should_fail=0
191+
mtu_set_if $dev $max_mtu $should_fail
192+
mtu_restore $dev
193+
194+
should_fail=1
195+
mtu_set_if $dev $((max_mtu + 1)) $should_fail
196+
mtu_restore $dev
197+
done
198+
199+
log_test "Test maximum MTU configuration"
200+
}
201+
202+
max_mtu_traffic_test()
203+
{
204+
local should_fail
205+
local max_mtu
206+
207+
RET=0
208+
209+
if ! ensure_compatible_min_max_mtu "max_mtu"; then
210+
log_test_xfail "Topology has incompatible maximum MTU values"
211+
return
212+
fi
213+
214+
max_mtu=$(min_max_mtu_get_if ${NETIFS[p1]} "max_mtu")
215+
216+
should_fail=0
217+
mtu_set_all_if $max_mtu
218+
mtu_test_ping4 $max_mtu $should_fail
219+
mtu_test_ping6 $max_mtu $should_fail
220+
mtu_restore_all_if
221+
222+
should_fail=1
223+
mtu_set_all_if $((max_mtu - 1))
224+
mtu_test_ping4 $max_mtu $should_fail
225+
mtu_test_ping6 $max_mtu $should_fail
226+
mtu_restore_all_if
227+
228+
log_test "Test traffic, packet size is maximum MTU"
229+
}
230+
231+
min_mtu_config_test()
232+
{
233+
local i
234+
235+
RET=0
236+
237+
for ((i = 1; i <= NUM_NETIFS; ++i)); do
238+
local dev=${NETIFS[p$i]}
239+
local min_mtu=$(min_max_mtu_get_if $dev "min_mtu")
240+
local should_fail
241+
242+
should_fail=0
243+
mtu_set_if $dev $min_mtu $should_fail
244+
mtu_restore $dev
245+
246+
should_fail=1
247+
mtu_set_if $dev $((min_mtu - 1)) $should_fail
248+
mtu_restore $dev
249+
done
250+
251+
log_test "Test minimum MTU configuration"
252+
}
253+
254+
min_mtu_traffic_test()
255+
{
256+
local should_fail=0
257+
local min_mtu
258+
259+
RET=0
260+
261+
if ! ensure_compatible_min_max_mtu "min_mtu"; then
262+
log_test_xfail "Topology has incompatible minimum MTU values"
263+
return
264+
fi
265+
266+
min_mtu=$(min_max_mtu_get_if ${NETIFS[p1]} "min_mtu")
267+
mtu_set_all_if $min_mtu
268+
mtu_test_ping4 $min_mtu $should_fail
269+
# Do not test minimum MTU with IPv6, as IPv6 requires higher MTU.
270+
271+
mtu_restore_all_if
272+
273+
log_test "Test traffic, packet size is minimum MTU"
274+
}
275+
276+
trap cleanup EXIT
277+
278+
setup_prepare
279+
setup_wait
280+
281+
tests_run
282+
283+
exit $EXIT_STATUS

0 commit comments

Comments
 (0)