Jiri Slaby
2014-06-30 11:50:38 UTC
=46rom: Michal Kube=C4=8Dek <***@suse.cz>
3.12-stable review patch. If anyone has any objections, please let me =
know.
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
commit da08143b85203b581f4a6461b149186b0e9592df upstream.
When combining real_dev's features and vlan_features, simple
bitwise AND is used. This doesn't work well for checksum
offloading features as if one set has NETIF_F_HW_CSUM and the
other NETIF_F_IP_CSUM and/or NETIF_F_IPV6_CSUM, we end up with
no checksum offloading. However, from the logical point of view
(how can_checksum_protocol() works), NETIF_F_HW_CSUM contains
the functionality of NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM so
that the result should be IP/IPV6.
Add helper function netdev_intersect_features() implementing
this logic and use it in vlan_dev_fix_features().
Signed-off-by: Michal Kubecek <***@suse.cz>
Signed-off-by: David S. Miller <***@davemloft.net>
Signed-off-by: Jiri Slaby <***@suse.cz>
---
include/linux/netdevice.h | 14 ++++++++++++++
net/8021q/vlan_dev.c | 4 ++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9f2a0cbc7d06..51bfd7a68272 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2892,6 +2892,20 @@ extern const char *netdev_drivername(const struc=
t net_device *dev);
=20
extern void linkwatch_run_queue(void);
=20
+static inline netdev_features_t netdev_intersect_features(netdev_featu=
res_t f1,
+ netdev_features_t f2)
+{
+ if (f1 & NETIF_F_GEN_CSUM)
+ f1 |=3D (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+ if (f2 & NETIF_F_GEN_CSUM)
+ f2 |=3D (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+ f1 &=3D f2;
+ if (f1 & NETIF_F_GEN_CSUM)
+ f1 &=3D ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+
+ return f1;
+}
+
static inline netdev_features_t netdev_get_wanted_features(
struct net_device *dev)
{
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 1b89bc7468de..0c21361fab30 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -694,9 +694,9 @@ static netdev_features_t vlan_dev_fix_features(stru=
ct net_device *dev,
struct net_device *real_dev =3D vlan_dev_priv(dev)->real_dev;
netdev_features_t old_features =3D features;
=20
- features &=3D real_dev->vlan_features;
+ features =3D netdev_intersect_features(features, real_dev->vlan_featu=
res);
features |=3D NETIF_F_RXCSUM;
- features &=3D real_dev->features;
+ features =3D netdev_intersect_features(features, real_dev->features);
=20
features |=3D old_features & NETIF_F_SOFT_FEATURES;
features |=3D NETIF_F_LLTX;
--=20
2.0.0
3.12-stable review patch. If anyone has any objections, please let me =
know.
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
commit da08143b85203b581f4a6461b149186b0e9592df upstream.
When combining real_dev's features and vlan_features, simple
bitwise AND is used. This doesn't work well for checksum
offloading features as if one set has NETIF_F_HW_CSUM and the
other NETIF_F_IP_CSUM and/or NETIF_F_IPV6_CSUM, we end up with
no checksum offloading. However, from the logical point of view
(how can_checksum_protocol() works), NETIF_F_HW_CSUM contains
the functionality of NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM so
that the result should be IP/IPV6.
Add helper function netdev_intersect_features() implementing
this logic and use it in vlan_dev_fix_features().
Signed-off-by: Michal Kubecek <***@suse.cz>
Signed-off-by: David S. Miller <***@davemloft.net>
Signed-off-by: Jiri Slaby <***@suse.cz>
---
include/linux/netdevice.h | 14 ++++++++++++++
net/8021q/vlan_dev.c | 4 ++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9f2a0cbc7d06..51bfd7a68272 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2892,6 +2892,20 @@ extern const char *netdev_drivername(const struc=
t net_device *dev);
=20
extern void linkwatch_run_queue(void);
=20
+static inline netdev_features_t netdev_intersect_features(netdev_featu=
res_t f1,
+ netdev_features_t f2)
+{
+ if (f1 & NETIF_F_GEN_CSUM)
+ f1 |=3D (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+ if (f2 & NETIF_F_GEN_CSUM)
+ f2 |=3D (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+ f1 &=3D f2;
+ if (f1 & NETIF_F_GEN_CSUM)
+ f1 &=3D ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
+
+ return f1;
+}
+
static inline netdev_features_t netdev_get_wanted_features(
struct net_device *dev)
{
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 1b89bc7468de..0c21361fab30 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -694,9 +694,9 @@ static netdev_features_t vlan_dev_fix_features(stru=
ct net_device *dev,
struct net_device *real_dev =3D vlan_dev_priv(dev)->real_dev;
netdev_features_t old_features =3D features;
=20
- features &=3D real_dev->vlan_features;
+ features =3D netdev_intersect_features(features, real_dev->vlan_featu=
res);
features |=3D NETIF_F_RXCSUM;
- features &=3D real_dev->features;
+ features =3D netdev_intersect_features(features, real_dev->features);
=20
features |=3D old_features & NETIF_F_SOFT_FEATURES;
features |=3D NETIF_F_LLTX;
--=20
2.0.0