Skip to content

Commit bfcb813

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: configure the MTU for switch ports
It is useful be able to configure port policers on a switch to accept frames of various sizes: - Increase the MTU for better throughput from the default of 1500 if it is known that there is no 10/100 Mbps device in the network. - Decrease the MTU to limit the latency of high-priority frames under congestion, or work around various network segments that add extra headers to packets which can't be fragmented. For DSA slave ports, this is mostly a pass-through callback, called through the regular ndo ops and at probe time (to ensure consistency across all supported switches). The CPU port is called with an MTU equal to the largest configured MTU of the slave ports. The assumption is that the user might want to sustain a bidirectional conversation with a partner over any switch port. The DSA master is configured the same as the CPU port, plus the tagger overhead. Since the MTU is by definition L2 payload (sans Ethernet header), it is up to each individual driver to figure out if it needs to do anything special for its frame tags on the CPU port (it shouldn't except in special cases). So the MTU does not contain the tagger overhead on the CPU port. However the MTU of the DSA master, minus the tagger overhead, is used as a proxy for the MTU of the CPU port, which does not have a net device. This is to avoid uselessly calling the .change_mtu function on the CPU port when nothing should change. So it is safe to assume that the DSA master and the CPU port MTUs are apart by exactly the tagger's overhead in bytes. Some changes were made around dsa_master_set_mtu(), function which was now removed, for 2 reasons: - dev_set_mtu() already calls dev_validate_mtu(), so it's redundant to do the same thing in DSA - __dev_set_mtu() returns 0 if ops->ndo_change_mtu is an absent method That is to say, there's no need for this function in DSA, we can safely call dev_set_mtu() directly, take the rtnl lock when necessary, and just propagate whatever errors get reported (since the user probably wants to be informed). Some inspiration (mainly in the MTU DSA notifier) was taken from a vaguely similar patch from Murali and Florian, who are credited as co-developers down below. Co-developed-by: Murali Krishna Policharla <[email protected]> Signed-off-by: Murali Krishna Policharla <[email protected]> Co-developed-by: Florian Fainelli <[email protected]> Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8c7da63 commit bfcb813

File tree

6 files changed

+181
-16
lines changed

6 files changed

+181
-16
lines changed

include/net/dsa.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,16 @@ struct dsa_switch_ops {
579579
struct devlink_param_gset_ctx *ctx);
580580
int (*devlink_param_set)(struct dsa_switch *ds, u32 id,
581581
struct devlink_param_gset_ctx *ctx);
582+
583+
/*
584+
* MTU change functionality. Switches can also adjust their MRU through
585+
* this method. By MTU, one understands the SDU (L2 payload) length.
586+
* If the switch needs to account for the DSA tag on the CPU port, this
587+
* method needs to to do so privately.
588+
*/
589+
int (*port_change_mtu)(struct dsa_switch *ds, int port,
590+
int new_mtu);
591+
int (*port_max_mtu)(struct dsa_switch *ds, int port);
582592
};
583593

584594
#define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \

net/dsa/dsa_priv.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum {
2222
DSA_NOTIFIER_MDB_DEL,
2323
DSA_NOTIFIER_VLAN_ADD,
2424
DSA_NOTIFIER_VLAN_DEL,
25+
DSA_NOTIFIER_MTU,
2526
};
2627

2728
/* DSA_NOTIFIER_AGEING_TIME */
@@ -61,6 +62,14 @@ struct dsa_notifier_vlan_info {
6162
int port;
6263
};
6364

65+
/* DSA_NOTIFIER_MTU */
66+
struct dsa_notifier_mtu_info {
67+
bool propagate_upstream;
68+
int sw_index;
69+
int port;
70+
int mtu;
71+
};
72+
6473
struct dsa_slave_priv {
6574
/* Copy of CPU port xmit for faster access in slave transmit hot path */
6675
struct sk_buff * (*xmit)(struct sk_buff *skb,
@@ -127,6 +136,8 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
127136
struct switchdev_trans *trans);
128137
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
129138
struct switchdev_trans *trans);
139+
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
140+
bool propagate_upstream);
130141
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
131142
u16 vid);
132143
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,

net/dsa/master.c

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -314,20 +314,6 @@ static const struct attribute_group dsa_group = {
314314
.attrs = dsa_slave_attrs,
315315
};
316316

317-
static void dsa_master_set_mtu(struct net_device *dev, struct dsa_port *cpu_dp)
318-
{
319-
unsigned int mtu = ETH_DATA_LEN + cpu_dp->tag_ops->overhead;
320-
int err;
321-
322-
rtnl_lock();
323-
if (mtu <= dev->max_mtu) {
324-
err = dev_set_mtu(dev, mtu);
325-
if (err)
326-
netdev_dbg(dev, "Unable to set MTU to include for DSA overheads\n");
327-
}
328-
rtnl_unlock();
329-
}
330-
331317
static void dsa_master_reset_mtu(struct net_device *dev)
332318
{
333319
int err;
@@ -344,7 +330,12 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
344330
{
345331
int ret;
346332

347-
dsa_master_set_mtu(dev, cpu_dp);
333+
rtnl_lock();
334+
ret = dev_set_mtu(dev, ETH_DATA_LEN + cpu_dp->tag_ops->overhead);
335+
rtnl_unlock();
336+
if (ret)
337+
netdev_warn(dev, "error %d setting MTU to include DSA overhead\n",
338+
ret);
348339

349340
/* If we use a tagging format that doesn't have an ethertype
350341
* field, make sure that all packets from this point on get

net/dsa/port.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,19 @@ int dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
297297
return ds->ops->port_egress_floods(ds, port, true, mrouter);
298298
}
299299

300+
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
301+
bool propagate_upstream)
302+
{
303+
struct dsa_notifier_mtu_info info = {
304+
.sw_index = dp->ds->index,
305+
.propagate_upstream = propagate_upstream,
306+
.port = dp->index,
307+
.mtu = new_mtu,
308+
};
309+
310+
return dsa_port_notify(dp, DSA_NOTIFIER_MTU, &info);
311+
}
312+
300313
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
301314
u16 vid)
302315
{

net/dsa/slave.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,96 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
12181218
return dsa_port_vid_del(dp, vid);
12191219
}
12201220

1221+
static int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
1222+
{
1223+
struct net_device *master = dsa_slave_to_master(dev);
1224+
struct dsa_port *dp = dsa_slave_to_port(dev);
1225+
struct dsa_slave_priv *p = netdev_priv(dev);
1226+
struct dsa_switch *ds = p->dp->ds;
1227+
struct dsa_port *cpu_dp;
1228+
int port = p->dp->index;
1229+
int largest_mtu = 0;
1230+
int new_master_mtu;
1231+
int old_master_mtu;
1232+
int mtu_limit;
1233+
int cpu_mtu;
1234+
int err, i;
1235+
1236+
if (!ds->ops->port_change_mtu)
1237+
return -EOPNOTSUPP;
1238+
1239+
for (i = 0; i < ds->num_ports; i++) {
1240+
int slave_mtu;
1241+
1242+
if (!dsa_is_user_port(ds, i))
1243+
continue;
1244+
1245+
/* During probe, this function will be called for each slave
1246+
* device, while not all of them have been allocated. That's
1247+
* ok, it doesn't change what the maximum is, so ignore it.
1248+
*/
1249+
if (!dsa_to_port(ds, i)->slave)
1250+
continue;
1251+
1252+
/* Pretend that we already applied the setting, which we
1253+
* actually haven't (still haven't done all integrity checks)
1254+
*/
1255+
if (i == port)
1256+
slave_mtu = new_mtu;
1257+
else
1258+
slave_mtu = dsa_to_port(ds, i)->slave->mtu;
1259+
1260+
if (largest_mtu < slave_mtu)
1261+
largest_mtu = slave_mtu;
1262+
}
1263+
1264+
cpu_dp = dsa_to_port(ds, port)->cpu_dp;
1265+
1266+
mtu_limit = min_t(int, master->max_mtu, dev->max_mtu);
1267+
old_master_mtu = master->mtu;
1268+
new_master_mtu = largest_mtu + cpu_dp->tag_ops->overhead;
1269+
if (new_master_mtu > mtu_limit)
1270+
return -ERANGE;
1271+
1272+
/* If the master MTU isn't over limit, there's no need to check the CPU
1273+
* MTU, since that surely isn't either.
1274+
*/
1275+
cpu_mtu = largest_mtu;
1276+
1277+
/* Start applying stuff */
1278+
if (new_master_mtu != old_master_mtu) {
1279+
err = dev_set_mtu(master, new_master_mtu);
1280+
if (err < 0)
1281+
goto out_master_failed;
1282+
1283+
/* We only need to propagate the MTU of the CPU port to
1284+
* upstream switches.
1285+
*/
1286+
err = dsa_port_mtu_change(cpu_dp, cpu_mtu, true);
1287+
if (err)
1288+
goto out_cpu_failed;
1289+
}
1290+
1291+
err = dsa_port_mtu_change(dp, new_mtu, false);
1292+
if (err)
1293+
goto out_port_failed;
1294+
1295+
dev->mtu = new_mtu;
1296+
1297+
return 0;
1298+
1299+
out_port_failed:
1300+
if (new_master_mtu != old_master_mtu)
1301+
dsa_port_mtu_change(cpu_dp, old_master_mtu -
1302+
cpu_dp->tag_ops->overhead,
1303+
true);
1304+
out_cpu_failed:
1305+
if (new_master_mtu != old_master_mtu)
1306+
dev_set_mtu(master, old_master_mtu);
1307+
out_master_failed:
1308+
return err;
1309+
}
1310+
12211311
static const struct ethtool_ops dsa_slave_ethtool_ops = {
12221312
.get_drvinfo = dsa_slave_get_drvinfo,
12231313
.get_regs_len = dsa_slave_get_regs_len,
@@ -1295,6 +1385,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
12951385
.ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
12961386
.ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
12971387
.ndo_get_devlink_port = dsa_slave_get_devlink_port,
1388+
.ndo_change_mtu = dsa_slave_change_mtu,
12981389
};
12991390

13001391
static struct device_type dsa_type = {
@@ -1465,7 +1556,10 @@ int dsa_slave_create(struct dsa_port *port)
14651556
slave_dev->priv_flags |= IFF_NO_QUEUE;
14661557
slave_dev->netdev_ops = &dsa_slave_netdev_ops;
14671558
slave_dev->min_mtu = 0;
1468-
slave_dev->max_mtu = ETH_MAX_MTU;
1559+
if (ds->ops->port_max_mtu)
1560+
slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index);
1561+
else
1562+
slave_dev->max_mtu = ETH_MAX_MTU;
14691563
SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
14701564

14711565
SET_NETDEV_DEV(slave_dev, port->ds->dev);
@@ -1483,6 +1577,15 @@ int dsa_slave_create(struct dsa_port *port)
14831577
p->xmit = cpu_dp->tag_ops->xmit;
14841578
port->slave = slave_dev;
14851579

1580+
rtnl_lock();
1581+
ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
1582+
rtnl_unlock();
1583+
if (ret && ret != -EOPNOTSUPP) {
1584+
dev_err(ds->dev, "error %d setting MTU on port %d\n",
1585+
ret, port->index);
1586+
goto out_free;
1587+
}
1588+
14861589
netif_carrier_off(slave_dev);
14871590

14881591
ret = dsa_slave_phy_setup(slave_dev);

net/dsa/switch.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,40 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
5252
return 0;
5353
}
5454

55+
static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
56+
struct dsa_notifier_mtu_info *info)
57+
{
58+
if (ds->index == info->sw_index)
59+
return (port == info->port) || dsa_is_dsa_port(ds, port);
60+
61+
if (!info->propagate_upstream)
62+
return false;
63+
64+
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
65+
return true;
66+
67+
return false;
68+
}
69+
70+
static int dsa_switch_mtu(struct dsa_switch *ds,
71+
struct dsa_notifier_mtu_info *info)
72+
{
73+
int port, ret;
74+
75+
if (!ds->ops->port_change_mtu)
76+
return -EOPNOTSUPP;
77+
78+
for (port = 0; port < ds->num_ports; port++) {
79+
if (dsa_switch_mtu_match(ds, port, info)) {
80+
ret = ds->ops->port_change_mtu(ds, port, info->mtu);
81+
if (ret)
82+
return ret;
83+
}
84+
}
85+
86+
return 0;
87+
}
88+
5589
static int dsa_switch_bridge_join(struct dsa_switch *ds,
5690
struct dsa_notifier_bridge_info *info)
5791
{
@@ -328,6 +362,9 @@ static int dsa_switch_event(struct notifier_block *nb,
328362
case DSA_NOTIFIER_VLAN_DEL:
329363
err = dsa_switch_vlan_del(ds, info);
330364
break;
365+
case DSA_NOTIFIER_MTU:
366+
err = dsa_switch_mtu(ds, info);
367+
break;
331368
default:
332369
err = -EOPNOTSUPP;
333370
break;

0 commit comments

Comments
 (0)