From: Mike Sinkovsky <msink@permonline.ru>
To: netdev@vger.kernel.org
Cc: msink@permonline.ru
Subject: [PATCH RFC] net: hardware limited MTU for 802.1Q frames
Date: Fri, 23 Mar 2012 15:51:26 +0500 [thread overview]
Message-ID: <1332499886-1126-1-git-send-email-msink@permonline.ru> (raw)
Some chips (WIZnet as example) have hardware limited MTU -
plain ethernet frame works with MTU 1500, but for 802.1Q
frames MTU must be limited to 1496.
This patch add callback in net_device_ops, called from 8021q
code to check for this hardware limitation.
If callback is not set in driver - vlan works as before,
in hope that underlaying device always can handle
additional 4 byte in frame length.
---
include/linux/netdevice.h | 20 ++++++++++++++++++++
net/8021q/vlan.c | 13 ++++++-------
net/8021q/vlan_dev.c | 8 ++++----
net/8021q/vlan_netlink.c | 4 ++--
4 files changed, 32 insertions(+), 13 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8debe29..3cbf2a4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -790,6 +790,13 @@ struct netdev_fcoe_hbainfo {
* of a device. If not defined, any request to change MTU will
* will return an error.
*
+ * int (*ndo_get_hard_mtu)(struct net_device *dev)
+ * If defined, returns hardware limit for MTU.
+ * Called when a slave device needs to set MTU, to make sure that
+ * this limit is not exceed.
+ * If not defined, dev->mtu is used in hope the underlying device can
+ * handle it.
+ *
* void (*ndo_tx_timeout)(struct net_device *dev);
* Callback uses when the transmitter has not made any progress
* for dev->watchdog ticks.
@@ -926,6 +933,7 @@ struct net_device_ops {
struct ifmap *map);
int (*ndo_change_mtu)(struct net_device *dev,
int new_mtu);
+ int (*ndo_get_hard_mtu)(struct net_device *dev);
int (*ndo_neigh_setup)(struct net_device *dev,
struct neigh_parms *);
void (*ndo_tx_timeout) (struct net_device *dev);
@@ -2677,6 +2685,18 @@ static inline bool netif_supports_nofcs(struct net_device *dev)
return dev->priv_flags & IFF_SUPP_NOFCS;
}
+static inline int netdev_get_mtu(struct net_device *dev, int hlen)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+ int mtu = dev->mtu;
+ if (ops->ndo_get_hard_mtu) {
+ int hard_mtu = ops->ndo_get_hard_mtu(dev);
+ if (mtu + hlen > hard_mtu)
+ mtu = hard_mtu - hlen;
+ }
+ return mtu;
+}
+
extern struct pernet_operations __net_initdata loopback_net_ops;
/* Logging, debugging and troubleshooting/diagnostic helpers. */
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index efea35b..ecf3089 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -238,10 +238,8 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
return -ENOBUFS;
dev_net_set(new_dev, net);
- /* need 4 bytes for extra VLAN header info,
- * hope the underlying device can handle it.
- */
- new_dev->mtu = real_dev->mtu;
+
+ new_dev->mtu = netdev_get_mtu(real_dev, VLAN_HLEN);
vlan_dev_priv(new_dev)->vlan_id = vlan_id;
vlan_dev_priv(new_dev)->real_dev = real_dev;
@@ -326,7 +324,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
struct net_device *dev = ptr;
struct vlan_group *grp;
struct vlan_info *vlan_info;
- int i, flgs;
+ int i, flgs, mtu;
struct net_device *vlandev;
struct vlan_dev_priv *vlan;
LIST_HEAD(list);
@@ -378,15 +376,16 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;
case NETDEV_CHANGEMTU:
+ mtu = netdev_get_mtu(dev, VLAN_HLEN);
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
- if (vlandev->mtu <= dev->mtu)
+ if (vlandev->mtu <= mtu)
continue;
- dev_set_mtu(vlandev, dev->mtu);
+ dev_set_mtu(vlandev, mtu);
}
break;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 9988d4a..bd52428 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -180,10 +180,10 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
{
- /* TODO: gotta make sure the underlying layer can handle it,
- * maybe an IFF_VLAN_CAPABLE flag for devices?
- */
- if (vlan_dev_priv(dev)->real_dev->mtu < new_mtu)
+ struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
+
+ /* make sure the underlying layer can handle it */
+ if (new_mtu > netdev_get_mtu(real_dev, VLAN_HLEN))
return -ERANGE;
dev->mtu = new_mtu;
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 5071136..c83420c 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -127,8 +127,8 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
return err;
if (!tb[IFLA_MTU])
- dev->mtu = real_dev->mtu;
- else if (dev->mtu > real_dev->mtu)
+ dev->mtu = netdev_get_mtu(real_dev, VLAN_HLEN);
+ else if (dev->mtu > netdev_get_mtu(real_dev, VLAN_HLEN))
return -EINVAL;
err = vlan_changelink(dev, tb, data);
next reply other threads:[~2012-03-23 10:51 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-23 10:51 Mike Sinkovsky [this message]
2012-03-23 14:41 ` [PATCH RFC] net: hardware limited MTU for 802.1Q frames David Lamparter
2012-03-23 18:34 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1332499886-1126-1-git-send-email-msink@permonline.ru \
--to=msink@permonline.ru \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).