* [PATCH] bonding: convert to ndo_fix_features
@ 2011-05-06 17:56 Michał Mirosław
2011-05-06 18:18 ` Jay Vosburgh
2011-05-07 13:22 ` [PATCH v2] " Michał Mirosław
0 siblings, 2 replies; 5+ messages in thread
From: Michał Mirosław @ 2011-05-06 17:56 UTC (permalink / raw)
To: netdev; +Cc: Jay Vosburgh, Andy Gospodarek
This should also fix updating of vlan_features and propagating changes to
VLAN devices on the bond.
Side effect: it allows user to force-disable some offloads on the bond
interface.
Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now.
BTW, What are the problems in creating VLAN devices on an empty bond
(as stated in one of bond_setup() comments)?
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
Note: This is only compile tested, yet.
drivers/net/bonding/bond_main.c | 133 +++++++++++++++------------------------
1 files changed, 50 insertions(+), 83 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 9a5feaf..04a2205 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -344,32 +344,6 @@ out:
}
/**
- * bond_has_challenged_slaves
- * @bond: the bond we're working on
- *
- * Searches the slave list. Returns 1 if a vlan challenged slave
- * was found, 0 otherwise.
- *
- * Assumes bond->lock is held.
- */
-static int bond_has_challenged_slaves(struct bonding *bond)
-{
- struct slave *slave;
- int i;
-
- bond_for_each_slave(bond, slave, i) {
- if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
- pr_debug("found VLAN challenged slave - %s\n",
- slave->dev->name);
- return 1;
- }
- }
-
- pr_debug("no VLAN challenged slaves found\n");
- return 0;
-}
-
-/**
* bond_next_vlan - safely skip to the next item in the vlans list.
* @bond: the bond we're working on
* @curr: item we're advancing from
@@ -1406,52 +1380,61 @@ static int bond_sethwaddr(struct net_device *bond_dev,
return 0;
}
-#define BOND_VLAN_FEATURES \
- (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
- NETIF_F_HW_VLAN_FILTER)
-
-/*
- * Compute the common dev->feature set available to all slaves. Some
- * feature bits are managed elsewhere, so preserve those feature bits
- * on the master device.
- */
-static int bond_compute_features(struct bonding *bond)
+static u32 bond_fix_features(struct net_device *dev, u32 features)
{
struct slave *slave;
- struct net_device *bond_dev = bond->dev;
- u32 features = bond_dev->features;
- u32 vlan_features = 0;
- unsigned short max_hard_header_len = max((u16)ETH_HLEN,
- bond_dev->hard_header_len);
+ struct bonding *bond = netdev_priv(dev);
+ u32 mask;
int i;
- features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
- features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY;
-
if (!bond->first_slave)
- goto done;
+ /* Disable adding VLANs to empty bond. But why? --mq */
+ return features | NETIF_F_VLAN_CHALLENGED;
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
+ features |= NETIF_F_ALL_FOR_ALL;
- vlan_features = bond->first_slave->dev->vlan_features;
bond_for_each_slave(bond, slave, i) {
features = netdev_increment_features(features,
slave->dev->features,
- NETIF_F_ONE_FOR_ALL);
+ mask);
+ }
+
+ return features;
+}
+
+#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \
+ NETIF_F_SOFT_FEATURES | \
+ NETIF_F_LRO)
+
+static void bond_compute_features(struct bonding *bond)
+{
+ struct slave *slave;
+ struct net_device *bond_dev = bond->dev;
+ u32 old_features, vlan_features = BOND_VLAN_FEATURES;
+ unsigned short max_hard_header_len = ETH_HLEN;
+ int i;
+
+ if (!bond->first_slave)
+ goto done;
+
+ bond_for_each_slave(bond, slave, i) {
vlan_features = netdev_increment_features(vlan_features,
- slave->dev->vlan_features,
- NETIF_F_ONE_FOR_ALL);
+ slave->dev->vlan_features, BOND_VLAN_FEATURES);
+
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
}
done:
- features |= (bond_dev->features & BOND_VLAN_FEATURES);
- bond_dev->features = netdev_fix_features(bond_dev, features);
- bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features);
+ bond_dev->vlan_features = vlan_features;
bond_dev->hard_header_len = max_hard_header_len;
- return 0;
+ old_features = bond_dev->features;
+ netdev_update_features(bond_dev);
+ if (old_features == bond_dev->features)
+ netdev_features_change(bond_dev);
}
static void bond_setup_by_slave(struct net_device *bond_dev,
@@ -1544,7 +1527,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct netdev_hw_addr *ha;
struct sockaddr addr;
int link_reporting;
- int old_features = bond_dev->features;
int res = 0;
if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
@@ -1577,16 +1559,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
bond_dev->name, slave_dev->name,
slave_dev->name, bond_dev->name);
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
}
} else {
pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
- if (bond->slave_cnt == 0) {
- /* First slave, and it is not VLAN challenged,
- * so remove the block of adding VLANs over the bond.
- */
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
- }
}
/*
@@ -1958,7 +1933,7 @@ err_free:
kfree(new_slave);
err_undo_flags:
- bond_dev->features = old_features;
+ bond_compute_features(bond);
return res;
}
@@ -1979,6 +1954,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent;
struct sockaddr addr;
+ u32 old_features = bond_dev->features;
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -2084,19 +2060,16 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
bond_dev->name, bond_dev->name);
pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
bond_dev->name);
}
- } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
- !bond_has_challenged_slaves(bond)) {
+ } else if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
+ old_features & NETIF_F_VLAN_CHALLENGED) {
pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
bond_dev->name, slave_dev->name, bond_dev->name);
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
}
write_unlock_bh(&bond->lock);
@@ -2269,9 +2242,7 @@ static int bond_release_all(struct net_device *bond_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
bond_dev->name, bond_dev->name);
pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -4347,11 +4318,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
static const struct ethtool_ops bond_ethtool_ops = {
.get_drvinfo = bond_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_flags = ethtool_op_get_flags,
};
static const struct net_device_ops bond_netdev_ops = {
@@ -4377,6 +4343,7 @@ static const struct net_device_ops bond_netdev_ops = {
#endif
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
+ .ndo_fix_features = bond_fix_features,
};
static void bond_destructor(struct net_device *bond_dev)
@@ -4432,14 +4399,14 @@ static void bond_setup(struct net_device *bond_dev)
* when there are slaves that are not hw accel
* capable
*/
- bond_dev->features |= (NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER);
- /* By default, we enable GRO on bonding devices.
- * Actual support requires lowlevel drivers are GRO ready.
- */
- bond_dev->features |= NETIF_F_GRO;
+ bond_dev->hw_features = BOND_VLAN_FEATURES |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+ bond_dev->features |= bond_dev->hw_features;
}
static void bond_work_cancel_all(struct bonding *bond)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] bonding: convert to ndo_fix_features
2011-05-06 17:56 [PATCH] bonding: convert to ndo_fix_features Michał Mirosław
@ 2011-05-06 18:18 ` Jay Vosburgh
2011-05-07 7:37 ` Michał Mirosław
2011-05-07 13:22 ` [PATCH v2] " Michał Mirosław
1 sibling, 1 reply; 5+ messages in thread
From: Jay Vosburgh @ 2011-05-06 18:18 UTC (permalink / raw)
To: Michał Mirosław; +Cc: netdev, Andy Gospodarek
Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:
>This should also fix updating of vlan_features and propagating changes to
>VLAN devices on the bond.
>
>Side effect: it allows user to force-disable some offloads on the bond
>interface.
>
>Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now.
>
>BTW, What are the problems in creating VLAN devices on an empty bond
>(as stated in one of bond_setup() comments)?
If there are no slaves, then the bond does not have a MAC
address assigned (because it gets its initial MAC from the first slave).
It's therefore impossible to pass a MAC address up to the VLAN
interface.
So the limitation is that the bond must have at least one slave
before a VLAN may be configured above it.
-J
>Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
>---
>
>Note: This is only compile tested, yet.
>
> drivers/net/bonding/bond_main.c | 133 +++++++++++++++------------------------
> 1 files changed, 50 insertions(+), 83 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 9a5feaf..04a2205 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -344,32 +344,6 @@ out:
> }
>
> /**
>- * bond_has_challenged_slaves
>- * @bond: the bond we're working on
>- *
>- * Searches the slave list. Returns 1 if a vlan challenged slave
>- * was found, 0 otherwise.
>- *
>- * Assumes bond->lock is held.
>- */
>-static int bond_has_challenged_slaves(struct bonding *bond)
>-{
>- struct slave *slave;
>- int i;
>-
>- bond_for_each_slave(bond, slave, i) {
>- if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
>- pr_debug("found VLAN challenged slave - %s\n",
>- slave->dev->name);
>- return 1;
>- }
>- }
>-
>- pr_debug("no VLAN challenged slaves found\n");
>- return 0;
>-}
>-
>-/**
> * bond_next_vlan - safely skip to the next item in the vlans list.
> * @bond: the bond we're working on
> * @curr: item we're advancing from
>@@ -1406,52 +1380,61 @@ static int bond_sethwaddr(struct net_device *bond_dev,
> return 0;
> }
>
>-#define BOND_VLAN_FEATURES \
>- (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
>- NETIF_F_HW_VLAN_FILTER)
>-
>-/*
>- * Compute the common dev->feature set available to all slaves. Some
>- * feature bits are managed elsewhere, so preserve those feature bits
>- * on the master device.
>- */
>-static int bond_compute_features(struct bonding *bond)
>+static u32 bond_fix_features(struct net_device *dev, u32 features)
> {
> struct slave *slave;
>- struct net_device *bond_dev = bond->dev;
>- u32 features = bond_dev->features;
>- u32 vlan_features = 0;
>- unsigned short max_hard_header_len = max((u16)ETH_HLEN,
>- bond_dev->hard_header_len);
>+ struct bonding *bond = netdev_priv(dev);
>+ u32 mask;
> int i;
>
>- features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
>- features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY;
>-
> if (!bond->first_slave)
>- goto done;
>+ /* Disable adding VLANs to empty bond. But why? --mq */
>+ return features | NETIF_F_VLAN_CHALLENGED;
>
>+ mask = features;
> features &= ~NETIF_F_ONE_FOR_ALL;
>+ features |= NETIF_F_ALL_FOR_ALL;
>
>- vlan_features = bond->first_slave->dev->vlan_features;
> bond_for_each_slave(bond, slave, i) {
> features = netdev_increment_features(features,
> slave->dev->features,
>- NETIF_F_ONE_FOR_ALL);
>+ mask);
>+ }
>+
>+ return features;
>+}
>+
>+#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \
>+ NETIF_F_SOFT_FEATURES | \
>+ NETIF_F_LRO)
>+
>+static void bond_compute_features(struct bonding *bond)
>+{
>+ struct slave *slave;
>+ struct net_device *bond_dev = bond->dev;
>+ u32 old_features, vlan_features = BOND_VLAN_FEATURES;
>+ unsigned short max_hard_header_len = ETH_HLEN;
>+ int i;
>+
>+ if (!bond->first_slave)
>+ goto done;
>+
>+ bond_for_each_slave(bond, slave, i) {
> vlan_features = netdev_increment_features(vlan_features,
>- slave->dev->vlan_features,
>- NETIF_F_ONE_FOR_ALL);
>+ slave->dev->vlan_features, BOND_VLAN_FEATURES);
>+
> if (slave->dev->hard_header_len > max_hard_header_len)
> max_hard_header_len = slave->dev->hard_header_len;
> }
>
> done:
>- features |= (bond_dev->features & BOND_VLAN_FEATURES);
>- bond_dev->features = netdev_fix_features(bond_dev, features);
>- bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features);
>+ bond_dev->vlan_features = vlan_features;
> bond_dev->hard_header_len = max_hard_header_len;
>
>- return 0;
>+ old_features = bond_dev->features;
>+ netdev_update_features(bond_dev);
>+ if (old_features == bond_dev->features)
>+ netdev_features_change(bond_dev);
> }
>
> static void bond_setup_by_slave(struct net_device *bond_dev,
>@@ -1544,7 +1527,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
> struct netdev_hw_addr *ha;
> struct sockaddr addr;
> int link_reporting;
>- int old_features = bond_dev->features;
> int res = 0;
>
> if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
>@@ -1577,16 +1559,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
> pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
> bond_dev->name, slave_dev->name,
> slave_dev->name, bond_dev->name);
>- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
> }
> } else {
> pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
>- if (bond->slave_cnt == 0) {
>- /* First slave, and it is not VLAN challenged,
>- * so remove the block of adding VLANs over the bond.
>- */
>- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
>- }
> }
>
> /*
>@@ -1958,7 +1933,7 @@ err_free:
> kfree(new_slave);
>
> err_undo_flags:
>- bond_dev->features = old_features;
>+ bond_compute_features(bond);
>
> return res;
> }
>@@ -1979,6 +1954,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
> struct bonding *bond = netdev_priv(bond_dev);
> struct slave *slave, *oldcurrent;
> struct sockaddr addr;
>+ u32 old_features = bond_dev->features;
>
> /* slave is not a slave or master is not master of this slave */
> if (!(slave_dev->flags & IFF_SLAVE) ||
>@@ -2084,19 +2060,16 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
> */
> memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
>
>- if (!bond->vlgrp) {
>- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
>- } else {
>+ if (bond->vlgrp) {
> pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
> bond_dev->name, bond_dev->name);
> pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
> bond_dev->name);
> }
>- } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
>- !bond_has_challenged_slaves(bond)) {
>+ } else if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
>+ old_features & NETIF_F_VLAN_CHALLENGED) {
> pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
> bond_dev->name, slave_dev->name, bond_dev->name);
>- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
> }
>
> write_unlock_bh(&bond->lock);
>@@ -2269,9 +2242,7 @@ static int bond_release_all(struct net_device *bond_dev)
> */
> memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
>
>- if (!bond->vlgrp) {
>- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
>- } else {
>+ if (bond->vlgrp) {
> pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
> bond_dev->name, bond_dev->name);
> pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
>@@ -4347,11 +4318,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
> static const struct ethtool_ops bond_ethtool_ops = {
> .get_drvinfo = bond_ethtool_get_drvinfo,
> .get_link = ethtool_op_get_link,
>- .get_tx_csum = ethtool_op_get_tx_csum,
>- .get_sg = ethtool_op_get_sg,
>- .get_tso = ethtool_op_get_tso,
>- .get_ufo = ethtool_op_get_ufo,
>- .get_flags = ethtool_op_get_flags,
> };
>
> static const struct net_device_ops bond_netdev_ops = {
>@@ -4377,6 +4343,7 @@ static const struct net_device_ops bond_netdev_ops = {
> #endif
> .ndo_add_slave = bond_enslave,
> .ndo_del_slave = bond_release,
>+ .ndo_fix_features = bond_fix_features,
> };
>
> static void bond_destructor(struct net_device *bond_dev)
>@@ -4432,14 +4399,14 @@ static void bond_setup(struct net_device *bond_dev)
> * when there are slaves that are not hw accel
> * capable
> */
>- bond_dev->features |= (NETIF_F_HW_VLAN_TX |
>- NETIF_F_HW_VLAN_RX |
>- NETIF_F_HW_VLAN_FILTER);
>
>- /* By default, we enable GRO on bonding devices.
>- * Actual support requires lowlevel drivers are GRO ready.
>- */
>- bond_dev->features |= NETIF_F_GRO;
>+ bond_dev->hw_features = BOND_VLAN_FEATURES |
>+ NETIF_F_HW_VLAN_TX |
>+ NETIF_F_HW_VLAN_RX |
>+ NETIF_F_HW_VLAN_FILTER;
>+
>+ bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
>+ bond_dev->features |= bond_dev->hw_features;
> }
>
> static void bond_work_cancel_all(struct bonding *bond)
>--
>1.7.2.5
>
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] bonding: convert to ndo_fix_features
2011-05-06 18:18 ` Jay Vosburgh
@ 2011-05-07 7:37 ` Michał Mirosław
0 siblings, 0 replies; 5+ messages in thread
From: Michał Mirosław @ 2011-05-07 7:37 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: netdev, Andy Gospodarek
On Fri, May 06, 2011 at 11:18:04AM -0700, Jay Vosburgh wrote:
> Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:
> >This should also fix updating of vlan_features and propagating changes to
> >VLAN devices on the bond.
> >
> >Side effect: it allows user to force-disable some offloads on the bond
> >interface.
> >
> >Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now.
> >
> >BTW, What are the problems in creating VLAN devices on an empty bond
> >(as stated in one of bond_setup() comments)?
> If there are no slaves, then the bond does not have a MAC
> address assigned (because it gets its initial MAC from the first slave).
> It's therefore impossible to pass a MAC address up to the VLAN
> interface.
>
> So the limitation is that the bond must have at least one slave
> before a VLAN may be configured above it.
Hmm. That might be worked aroud by generating random MAC then. This would
allow the user to first set a new MAC, create VLANs and then add slaves
when they show up.
Best Regards,
Michał Mirosław
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] bonding: convert to ndo_fix_features
2011-05-06 17:56 [PATCH] bonding: convert to ndo_fix_features Michał Mirosław
2011-05-06 18:18 ` Jay Vosburgh
@ 2011-05-07 13:22 ` Michał Mirosław
2011-05-12 22:46 ` David Miller
1 sibling, 1 reply; 5+ messages in thread
From: Michał Mirosław @ 2011-05-07 13:22 UTC (permalink / raw)
To: netdev; +Cc: Jay Vosburgh, Andy Gospodarek
This should also fix updating of vlan_features and propagating changes to
VLAN devices on the bond.
Side effect: it allows user to force-disable some offloads on the bond
interface.
Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now.
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
Note: Depends on netdev_change_features() patch.
v2: - use netdev_change_features()
- fix locking around bond_compute_features()
drivers/net/bonding/bond_main.c | 161 ++++++++++++++++----------------------
1 files changed, 68 insertions(+), 93 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 9a5feaf..36ff316 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -344,32 +344,6 @@ out:
}
/**
- * bond_has_challenged_slaves
- * @bond: the bond we're working on
- *
- * Searches the slave list. Returns 1 if a vlan challenged slave
- * was found, 0 otherwise.
- *
- * Assumes bond->lock is held.
- */
-static int bond_has_challenged_slaves(struct bonding *bond)
-{
- struct slave *slave;
- int i;
-
- bond_for_each_slave(bond, slave, i) {
- if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
- pr_debug("found VLAN challenged slave - %s\n",
- slave->dev->name);
- return 1;
- }
- }
-
- pr_debug("no VLAN challenged slaves found\n");
- return 0;
-}
-
-/**
* bond_next_vlan - safely skip to the next item in the vlans list.
* @bond: the bond we're working on
* @curr: item we're advancing from
@@ -1406,52 +1380,68 @@ static int bond_sethwaddr(struct net_device *bond_dev,
return 0;
}
-#define BOND_VLAN_FEATURES \
- (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
- NETIF_F_HW_VLAN_FILTER)
-
-/*
- * Compute the common dev->feature set available to all slaves. Some
- * feature bits are managed elsewhere, so preserve those feature bits
- * on the master device.
- */
-static int bond_compute_features(struct bonding *bond)
+static u32 bond_fix_features(struct net_device *dev, u32 features)
{
struct slave *slave;
- struct net_device *bond_dev = bond->dev;
- u32 features = bond_dev->features;
- u32 vlan_features = 0;
- unsigned short max_hard_header_len = max((u16)ETH_HLEN,
- bond_dev->hard_header_len);
+ struct bonding *bond = netdev_priv(dev);
+ u32 mask;
int i;
- features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
- features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY;
+ read_lock(&bond->lock);
- if (!bond->first_slave)
- goto done;
+ if (!bond->first_slave) {
+ /* Disable adding VLANs to empty bond. But why? --mq */
+ features |= NETIF_F_VLAN_CHALLENGED;
+ goto out;
+ }
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
+ features |= NETIF_F_ALL_FOR_ALL;
- vlan_features = bond->first_slave->dev->vlan_features;
bond_for_each_slave(bond, slave, i) {
features = netdev_increment_features(features,
slave->dev->features,
- NETIF_F_ONE_FOR_ALL);
+ mask);
+ }
+
+out:
+ read_unlock(&bond->lock);
+ return features;
+}
+
+#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \
+ NETIF_F_SOFT_FEATURES | \
+ NETIF_F_LRO)
+
+static void bond_compute_features(struct bonding *bond)
+{
+ struct slave *slave;
+ struct net_device *bond_dev = bond->dev;
+ u32 vlan_features = BOND_VLAN_FEATURES;
+ unsigned short max_hard_header_len = ETH_HLEN;
+ int i;
+
+ read_lock(&bond->lock);
+
+ if (!bond->first_slave)
+ goto done;
+
+ bond_for_each_slave(bond, slave, i) {
vlan_features = netdev_increment_features(vlan_features,
- slave->dev->vlan_features,
- NETIF_F_ONE_FOR_ALL);
+ slave->dev->vlan_features, BOND_VLAN_FEATURES);
+
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
}
done:
- features |= (bond_dev->features & BOND_VLAN_FEATURES);
- bond_dev->features = netdev_fix_features(bond_dev, features);
- bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features);
+ bond_dev->vlan_features = vlan_features;
bond_dev->hard_header_len = max_hard_header_len;
- return 0;
+ read_unlock(&bond->lock);
+
+ netdev_change_features(bond_dev);
}
static void bond_setup_by_slave(struct net_device *bond_dev,
@@ -1544,7 +1534,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct netdev_hw_addr *ha;
struct sockaddr addr;
int link_reporting;
- int old_features = bond_dev->features;
int res = 0;
if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
@@ -1577,16 +1566,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
bond_dev->name, slave_dev->name,
slave_dev->name, bond_dev->name);
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
}
} else {
pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
- if (bond->slave_cnt == 0) {
- /* First slave, and it is not VLAN challenged,
- * so remove the block of adding VLANs over the bond.
- */
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
- }
}
/*
@@ -1775,10 +1757,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
new_slave->delay = 0;
new_slave->link_failure_count = 0;
- bond_compute_features(bond);
-
write_unlock_bh(&bond->lock);
+ bond_compute_features(bond);
+
read_lock(&bond->lock);
new_slave->last_arp_rx = jiffies;
@@ -1958,7 +1940,7 @@ err_free:
kfree(new_slave);
err_undo_flags:
- bond_dev->features = old_features;
+ bond_compute_features(bond);
return res;
}
@@ -1979,6 +1961,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent;
struct sockaddr addr;
+ u32 old_features = bond_dev->features;
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -2039,8 +2022,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* release the slave from its bond */
bond_detach_slave(bond, slave);
- bond_compute_features(bond);
-
if (bond->primary_slave == slave)
bond->primary_slave = NULL;
@@ -2084,23 +2065,22 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
bond_dev->name, bond_dev->name);
pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
bond_dev->name);
}
- } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
- !bond_has_challenged_slaves(bond)) {
+ }
+
+ write_unlock_bh(&bond->lock);
+ unblock_netpoll_tx();
+
+ bond_compute_features(bond);
+ if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
+ (old_features & NETIF_F_VLAN_CHALLENGED))
pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
bond_dev->name, slave_dev->name, bond_dev->name);
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
- }
-
- write_unlock_bh(&bond->lock);
- unblock_netpoll_tx();
/* must do this from outside any spinlocks */
bond_destroy_slave_symlinks(bond_dev, slave_dev);
@@ -2219,8 +2199,6 @@ static int bond_release_all(struct net_device *bond_dev)
bond_alb_deinit_slave(bond, slave);
}
- bond_compute_features(bond);
-
bond_destroy_slave_symlinks(bond_dev, slave_dev);
bond_del_vlans_from_slave(bond, slave_dev);
@@ -2269,9 +2247,7 @@ static int bond_release_all(struct net_device *bond_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
bond_dev->name, bond_dev->name);
pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -2282,6 +2258,9 @@ static int bond_release_all(struct net_device *bond_dev)
out:
write_unlock_bh(&bond->lock);
+
+ bond_compute_features(bond);
+
return 0;
}
@@ -4347,11 +4326,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
static const struct ethtool_ops bond_ethtool_ops = {
.get_drvinfo = bond_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_flags = ethtool_op_get_flags,
};
static const struct net_device_ops bond_netdev_ops = {
@@ -4377,6 +4351,7 @@ static const struct net_device_ops bond_netdev_ops = {
#endif
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
+ .ndo_fix_features = bond_fix_features,
};
static void bond_destructor(struct net_device *bond_dev)
@@ -4432,14 +4407,14 @@ static void bond_setup(struct net_device *bond_dev)
* when there are slaves that are not hw accel
* capable
*/
- bond_dev->features |= (NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER);
- /* By default, we enable GRO on bonding devices.
- * Actual support requires lowlevel drivers are GRO ready.
- */
- bond_dev->features |= NETIF_F_GRO;
+ bond_dev->hw_features = BOND_VLAN_FEATURES |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+ bond_dev->features |= bond_dev->hw_features;
}
static void bond_work_cancel_all(struct bonding *bond)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] bonding: convert to ndo_fix_features
2011-05-07 13:22 ` [PATCH v2] " Michał Mirosław
@ 2011-05-12 22:46 ` David Miller
0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2011-05-12 22:46 UTC (permalink / raw)
To: mirq-linux; +Cc: netdev, fubar, andy
From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Date: Sat, 7 May 2011 15:22:17 +0200 (CEST)
> This should also fix updating of vlan_features and propagating changes to
> VLAN devices on the bond.
>
> Side effect: it allows user to force-disable some offloads on the bond
> interface.
>
> Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now.
>
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Applied.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2011-05-12 22:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-06 17:56 [PATCH] bonding: convert to ndo_fix_features Michał Mirosław
2011-05-06 18:18 ` Jay Vosburgh
2011-05-07 7:37 ` Michał Mirosław
2011-05-07 13:22 ` [PATCH v2] " Michał Mirosław
2011-05-12 22:46 ` David Miller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.