aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-11-02 22:52:24 -0500
committerDavid S. Miller <davem@davemloft.net>2015-11-02 22:52:24 -0500
commita176ded3f4bdbd267bc9a79bde12d984c8c517b2 (patch)
tree48a4bb01acaecc60bd9d87c2dd4c4959e926b59e
parent12d4309636d30770b54985be05ac512131f328b8 (diff)
parent52bc67168109ade61014a36feedf09f4bc53d8f1 (diff)
downloadnfc-fixes-a176ded3f4bdbd267bc9a79bde12d984c8c517b2.tar.gz
Merge branch 'bonding-actor-updates'
Mahesh Bandewar says: ==================== re-org actor admin/oper key updates I was observing machines entering into weird LACP state when the partner is in passive mode. This issue is not because of the partners in passive state but probably because of some operational key update which is pushing the state-machine is that weird state. This was happening randomly on about 1% of the machine (when the sample size is a large set of machines with a variety of NICs/ports bonded). In this patch-series I'm attempting to unify the logic of actor-key / operational-key changes to one place to avoid possible errors in update. Also this eliminates the need for the event-handler to decide if the key needs update. After this patch-set none of the machines (from same sample set) were exhibiting LACP-weirdness that was observed earlier. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_3ad.c113
-rw-r--r--drivers/net/bonding/bond_main.c14
-rw-r--r--include/net/bond_3ad.h3
3 files changed, 54 insertions, 76 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3c45358844eb94..940e2ebbdea81e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -127,6 +127,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
struct port *port);
static void ad_marker_response_received(struct bond_marker *marker,
struct port *port);
+static void ad_update_actor_keys(struct port *port, bool reset);
/* ================= api to bonding and kernel code ================== */
@@ -327,14 +328,12 @@ static u16 __get_link_speed(struct port *port)
static u8 __get_duplex(struct port *port)
{
struct slave *slave = port->slave;
- u8 retval;
+ u8 retval = 0x0;
/* handling a special case: when the configuration starts with
* link down, it sets the duplex to 0.
*/
- if (slave->link != BOND_LINK_UP) {
- retval = 0x0;
- } else {
+ if (slave->link == BOND_LINK_UP) {
switch (slave->duplex) {
case DUPLEX_FULL:
retval = 0x1;
@@ -1953,14 +1952,7 @@ void bond_3ad_bind_slave(struct slave *slave)
* user key
*/
port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
- port->actor_admin_port_key |= __get_duplex(port);
- port->actor_admin_port_key |= (__get_link_speed(port) << 1);
- port->actor_oper_port_key = port->actor_admin_port_key;
- /* if the port is not full duplex, then the port should be not
- * lacp Enabled
- */
- if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS))
- port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+ ad_update_actor_keys(port, false);
/* actor system is the bond's system */
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
port->actor_system_priority =
@@ -2310,45 +2302,60 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
}
/**
- * bond_3ad_adapter_speed_changed - handle a slave's speed change indication
- * @slave: slave struct to work on
+ * ad_update_actor_keys - Update the oper / admin keys for a port based on
+ * its current speed and duplex settings.
*
- * Handle reselection of aggregator (if needed) for this port.
+ * @port: the port we'are looking at
+ * @reset: Boolean to just reset the speed and the duplex part of the key
+ *
+ * The logic to change the oper / admin keys is:
+ * (a) A full duplex port can participate in LACP with partner.
+ * (b) When the speed is changed, LACP need to be reinitiated.
*/
-void bond_3ad_adapter_speed_changed(struct slave *slave)
+static void ad_update_actor_keys(struct port *port, bool reset)
{
- struct port *port;
-
- port = &(SLAVE_AD_INFO(slave)->port);
-
- /* if slave is null, the whole port is not initialized */
- if (!port->slave) {
- netdev_warn(slave->bond->dev, "speed changed for uninitialized port on %s\n",
- slave->dev->name);
- return;
+ u8 duplex = 0;
+ u16 ospeed = 0, speed = 0;
+ u16 old_oper_key = port->actor_oper_port_key;
+
+ port->actor_admin_port_key &= ~(AD_SPEED_KEY_MASKS|AD_DUPLEX_KEY_MASKS);
+ if (!reset) {
+ speed = __get_link_speed(port);
+ ospeed = (old_oper_key & AD_SPEED_KEY_MASKS) >> 1;
+ duplex = __get_duplex(port);
+ port->actor_admin_port_key |= (speed << 1) | duplex;
}
-
- spin_lock_bh(&slave->bond->mode_lock);
-
- port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS;
- port->actor_admin_port_key |= __get_link_speed(port) << 1;
port->actor_oper_port_key = port->actor_admin_port_key;
- netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number);
- /* there is no need to reselect a new aggregator, just signal the
- * state machines to reinitialize
- */
- port->sm_vars |= AD_PORT_BEGIN;
- spin_unlock_bh(&slave->bond->mode_lock);
+ if (old_oper_key != port->actor_oper_port_key) {
+ /* Only 'duplex' port participates in LACP */
+ if (duplex)
+ port->sm_vars |= AD_PORT_LACP_ENABLED;
+ else
+ port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+
+ if (!reset) {
+ if (!speed) {
+ netdev_err(port->slave->dev,
+ "speed changed to 0 for port %s",
+ port->slave->dev->name);
+ } else if (duplex && ospeed != speed) {
+ /* Speed change restarts LACP state-machine */
+ port->sm_vars |= AD_PORT_BEGIN;
+ }
+ }
+ }
}
/**
- * bond_3ad_adapter_duplex_changed - handle a slave's duplex change indication
+ * bond_3ad_adapter_speed_duplex_changed - handle a slave's speed / duplex
+ * change indication
+ *
* @slave: slave struct to work on
*
* Handle reselection of aggregator (if needed) for this port.
*/
-void bond_3ad_adapter_duplex_changed(struct slave *slave)
+void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
{
struct port *port;
@@ -2356,25 +2363,16 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
- netdev_warn(slave->bond->dev, "duplex changed for uninitialized port on %s\n",
+ netdev_warn(slave->bond->dev,
+ "speed/duplex changed for uninitialized port %s\n",
slave->dev->name);
return;
}
spin_lock_bh(&slave->bond->mode_lock);
-
- port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS;
- port->actor_admin_port_key |= __get_duplex(port);
- port->actor_oper_port_key = port->actor_admin_port_key;
- netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n",
+ ad_update_actor_keys(port, false);
+ netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
port->actor_port_number, slave->dev->name);
- if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
- port->sm_vars |= AD_PORT_LACP_ENABLED;
- /* there is no need to reselect a new aggregator, just signal the
- * state machines to reinitialize
- */
- port->sm_vars |= AD_PORT_BEGIN;
-
spin_unlock_bh(&slave->bond->mode_lock);
}
@@ -2406,26 +2404,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
* on link up we are forcing recheck on the duplex and speed since
* some of he adaptors(ce1000.lan) report.
*/
- port->actor_admin_port_key &= ~(AD_DUPLEX_KEY_MASKS|AD_SPEED_KEY_MASKS);
if (link == BOND_LINK_UP) {
port->is_enabled = true;
- port->actor_admin_port_key |=
- (__get_link_speed(port) << 1) | __get_duplex(port);
- if (port->actor_admin_port_key & AD_DUPLEX_KEY_MASKS)
- port->sm_vars |= AD_PORT_LACP_ENABLED;
+ ad_update_actor_keys(port, false);
} else {
/* link has failed */
port->is_enabled = false;
- port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+ ad_update_actor_keys(port, true);
}
- port->actor_oper_port_key = port->actor_admin_port_key;
netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
port->actor_port_number,
link == BOND_LINK_UP ? "UP" : "DOWN");
- /* there is no need to reselect a new aggregator, just signal the
- * state machines to reinitialize
- */
- port->sm_vars |= AD_PORT_BEGIN;
spin_unlock_bh(&slave->bond->mode_lock);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d0f23cd6e236b0..b4351caf8e013d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2943,8 +2943,6 @@ static int bond_slave_netdev_event(unsigned long event,
struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary;
struct bonding *bond;
struct net_device *bond_dev;
- u32 old_speed;
- u8 old_duplex;
/* A netdev event can be generated while enslaving a device
* before netdev_rx_handler_register is called in which case
@@ -2965,17 +2963,9 @@ static int bond_slave_netdev_event(unsigned long event,
break;
case NETDEV_UP:
case NETDEV_CHANGE:
- old_speed = slave->speed;
- old_duplex = slave->duplex;
-
bond_update_speed_duplex(slave);
-
- if (BOND_MODE(bond) == BOND_MODE_8023AD) {
- if (old_speed != slave->speed)
- bond_3ad_adapter_speed_changed(slave);
- if (old_duplex != slave->duplex)
- bond_3ad_adapter_duplex_changed(slave);
- }
+ if (BOND_MODE(bond) == BOND_MODE_8023AD)
+ bond_3ad_adapter_speed_duplex_changed(slave);
/* Fallthrough */
case NETDEV_DOWN:
/* Refresh slave-array if applicable!
diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h
index c2a40a172fcdde..f1fbc3b119623d 100644
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -297,8 +297,7 @@ void bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
void bond_3ad_state_machine_handler(struct work_struct *);
void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
-void bond_3ad_adapter_speed_changed(struct slave *slave);
-void bond_3ad_adapter_duplex_changed(struct slave *slave);
+void bond_3ad_adapter_speed_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
int __bond_3ad_get_active_agg_info(struct bonding *bond,