diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 276 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 181 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 52 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 34 |
4 files changed, 361 insertions, 182 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 0ddf4c66afe..881914bc4e9 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -93,7 +93,7 @@ // compare MAC addresses #define MAC_ADDRESS_COMPARE(A, B) memcmp(A, B, ETH_ALEN) -static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; +static struct mac_addr null_mac_addr = { { 0, 0, 0, 0, 0, 0 } }; static u16 ad_ticks_per_sec; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; @@ -129,9 +129,8 @@ static void ad_marker_response_received(struct bond_marker *marker, struct port */ static inline struct bonding *__get_bond_by_port(struct port *port) { - if (port->slave == NULL) { + if (port->slave == NULL) return NULL; - } return bond_get_bond_by_slave(port->slave); } @@ -144,9 +143,8 @@ static inline struct bonding *__get_bond_by_port(struct port *port) */ static inline struct port *__get_first_port(struct bonding *bond) { - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) return NULL; - } return &(SLAVE_AD_INFO(bond->first_slave).port); } @@ -164,9 +162,8 @@ static inline struct port *__get_next_port(struct port *port) struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->first_slave)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) return NULL; - } return &(SLAVE_AD_INFO(slave->next).port); } @@ -183,9 +180,8 @@ static inline struct aggregator *__get_first_agg(struct port *port) struct bonding *bond = __get_bond_by_port(port); // If there's no bond for this port, or bond has no slaves - if ((bond == NULL) || (bond->slave_cnt == 0)) { + if ((bond == NULL) || (bond->slave_cnt == 0)) return NULL; - } return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } @@ -203,9 +199,8 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->first_slave)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) return NULL; - } return &(SLAVE_AD_INFO(slave->next).aggregator); } @@ -240,9 +235,8 @@ static inline void __enable_port(struct port *port) { struct slave *slave = port->slave; - if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) { + if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) bond_set_slave_active_flags(slave); - } } /** @@ -252,7 +246,7 @@ static inline void __enable_port(struct port *port) */ static inline int __port_is_enabled(struct port *port) { - return(port->slave->state == BOND_STATE_ACTIVE); + return port->slave->state == BOND_STATE_ACTIVE; } /** @@ -265,9 +259,8 @@ static inline u32 __get_agg_selection_mode(struct port *port) { struct bonding *bond = __get_bond_by_port(port); - if (bond == NULL) { + if (bond == NULL) return BOND_AD_STABLE; - } return BOND_AD_INFO(bond).agg_select_mode; } @@ -281,9 +274,8 @@ static inline int __check_agg_selection_timer(struct port *port) { struct bonding *bond = __get_bond_by_port(port); - if (bond == NULL) { + if (bond == NULL) return 0; - } return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0; } @@ -328,9 +320,9 @@ static u16 __get_link_speed(struct port *port) * link down, it sets the speed to 0. * This is done in spite of the fact that the e100 driver reports 0 to be * compatible with MVT in the future.*/ - if (slave->link != BOND_LINK_UP) { - speed=0; - } else { + if (slave->link != BOND_LINK_UP) + speed = 0; + else { switch (slave->speed) { case SPEED_10: speed = AD_LINK_SPEED_BITMASK_10MBPS; @@ -375,18 +367,18 @@ static u8 __get_duplex(struct port *port) // 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) + retval = 0x0; + else { switch (slave->duplex) { case DUPLEX_FULL: - retval=0x1; + retval = 0x1; pr_debug("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: - retval=0x0; + retval = 0x0; pr_debug("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; @@ -419,15 +411,14 @@ static inline void __initialize_port_locks(struct port *port) */ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par) { - u16 retval=0; //to silence the compiler + u16 retval = 0; /* to silence the compiler */ switch (timer_type) { case AD_CURRENT_WHILE_TIMER: // for rx machine usage - if (par) { // for short or long timeout + if (par) retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout - } else { + else retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout - } break; case AD_ACTOR_CHURN_TIMER: // for local churn machine retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec); @@ -519,11 +510,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) port->actor_oper_port_state &= ~AD_STATE_DEFAULTED; // set the partner sync. to on if the partner is sync. and the port is matched - if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) { + if ((port->sm_vars & AD_PORT_MATCHED) + && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) partner->port_state |= AD_STATE_SYNCHRONIZATION; - } else { + else partner->port_state &= ~AD_STATE_SYNCHRONIZATION; - } } } @@ -653,7 +644,7 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) */ static void __attach_bond_to_agg(struct port *port) { - port=NULL; // just to satisfy the compiler + port = NULL; /* just to satisfy the compiler */ // This function does nothing since the parser/multiplexer of the receive // and the parser/multiplexer of the aggregator are already combined } @@ -668,7 +659,7 @@ static void __attach_bond_to_agg(struct port *port) */ static void __detach_bond_from_agg(struct port *port) { - port=NULL; // just to satisfy the compiler + port = NULL; /* just to satisfy the compiler */ // This function does nothing sience the parser/multiplexer of the receive // and the parser/multiplexer of the aggregator are already combined } @@ -685,7 +676,9 @@ static int __agg_ports_are_ready(struct aggregator *aggregator) if (aggregator) { // scan all ports in this aggregator to verfy if they are all ready - for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) { + for (port = aggregator->lag_ports; + port; + port = port->next_port_in_aggregator) { if (!(port->sm_vars & AD_PORT_READY_N)) { retval = 0; break; @@ -706,12 +699,12 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) { struct port *port; - for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) { - if (val) { + for (port = aggregator->lag_ports; port; + port = port->next_port_in_aggregator) { + if (val) port->sm_vars |= AD_PORT_READY; - } else { + else port->sm_vars &= ~AD_PORT_READY; - } } } @@ -722,7 +715,7 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) */ static u32 __get_agg_bandwidth(struct aggregator *aggregator) { - u32 bandwidth=0; + u32 bandwidth = 0; u32 basic_speed; if (aggregator->num_of_ports) { @@ -744,7 +737,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) bandwidth = aggregator->num_of_ports * 10000; break; default: - bandwidth=0; // to silent the compilor .... + bandwidth = 0; /*to silence the compiler ....*/ } } return bandwidth; @@ -835,9 +828,8 @@ static int ad_lacpdu_send(struct port *port) int length = sizeof(struct lacpdu_header); skb = dev_alloc_skb(length); - if (!skb) { + if (!skb) return -ENOMEM; - } skb->dev = slave->dev; skb_reset_mac_header(skb); @@ -876,9 +868,8 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) int length = sizeof(struct bond_marker_header); skb = dev_alloc_skb(length + 16); - if (!skb) { + if (!skb) return -ENOMEM; - } skb_reserve(skb, 16); @@ -919,9 +910,10 @@ static void ad_mux_machine(struct port *port) } else { switch (port->sm_mux_state) { case AD_MUX_DETACHED: - if ((port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if SELECTED or STANDBY + if ((port->sm_vars & AD_PORT_SELECTED) + || (port->sm_vars & AD_PORT_STANDBY)) + /* if SELECTED or STANDBY */ port->sm_mux_state = AD_MUX_WAITING; // next state - } break; case AD_MUX_WAITING: // if SELECTED == FALSE return to DETACH state @@ -935,18 +927,18 @@ static void ad_mux_machine(struct port *port) } // check if the wait_while_timer expired - if (port->sm_mux_timer_counter && !(--port->sm_mux_timer_counter)) { + if (port->sm_mux_timer_counter + && !(--port->sm_mux_timer_counter)) port->sm_vars |= AD_PORT_READY_N; - } // in order to withhold the selection logic to check all ports READY_N value // every callback cycle to update ready variable, we check READY_N and update READY here __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); // if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state - if ((port->sm_vars & AD_PORT_READY) && !port->sm_mux_timer_counter) { + if ((port->sm_vars & AD_PORT_READY) + && !port->sm_mux_timer_counter) port->sm_mux_state = AD_MUX_ATTACHED; // next state - } break; case AD_MUX_ATTACHED: // check also if agg_select_timer expired(so the edable port will take place only after this timer) @@ -1041,13 +1033,14 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // check if state machine should change state // first, check if port was reinitialized - if (port->sm_vars & AD_PORT_BEGIN) { - port->sm_rx_state = AD_RX_INITIALIZE; // next state - } + if (port->sm_vars & AD_PORT_BEGIN) + /* next state */ + port->sm_rx_state = AD_RX_INITIALIZE; // check if port is not enabled - else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) { - port->sm_rx_state = AD_RX_PORT_DISABLED; // next state - } + else if (!(port->sm_vars & AD_PORT_BEGIN) + && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) + /* next state */ + port->sm_rx_state = AD_RX_PORT_DISABLED; // check if new lacpdu arrived else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) { port->sm_rx_timer_counter = 0; // zero timer @@ -1069,13 +1062,16 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // if no lacpdu arrived and no timer is on switch (port->sm_rx_state) { case AD_RX_PORT_DISABLED: - if (port->sm_vars & AD_PORT_MOVED) { + if (port->sm_vars & AD_PORT_MOVED) port->sm_rx_state = AD_RX_INITIALIZE; // next state - } else if (port->is_enabled && (port->sm_vars & AD_PORT_LACP_ENABLED)) { + else if (port->is_enabled + && (port->sm_vars + & AD_PORT_LACP_ENABLED)) port->sm_rx_state = AD_RX_EXPIRED; // next state - } else if (port->is_enabled && ((port->sm_vars & AD_PORT_LACP_ENABLED) == 0)) { + else if (port->is_enabled + && ((port->sm_vars + & AD_PORT_LACP_ENABLED) == 0)) port->sm_rx_state = AD_RX_LACP_DISABLED; // next state - } break; default: //to silence the compiler break; @@ -1091,11 +1087,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: - if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { + if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) port->sm_vars &= ~AD_PORT_LACP_ENABLED; - } else { + else port->sm_vars |= AD_PORT_LACP_ENABLED; - } port->sm_vars &= ~AD_PORT_SELECTED; __record_default(port); port->actor_oper_port_state &= ~AD_STATE_EXPIRED; @@ -1149,9 +1144,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // verify that if the aggregator is enabled, the port is enabled too. //(because if the link goes down for a short time, the 802.3ad will not // catch it, and the port will continue to be disabled) - if (port->aggregator && port->aggregator->is_active && !__port_is_enabled(port)) { + if (port->aggregator + && port->aggregator->is_active + && !__port_is_enabled(port)) __enable_port(port); - } break; default: //to silence the compiler break; @@ -1183,7 +1179,8 @@ static void ad_tx_machine(struct port *port) } } // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND - port->sm_tx_timer_counter=ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; + port->sm_tx_timer_counter = + ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; } } @@ -1216,9 +1213,9 @@ static void ad_periodic_machine(struct port *port) // If not expired, check if there is some new timeout parameter from the partner state switch (port->sm_periodic_state) { case AD_FAST_PERIODIC: - if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state + & AD_STATE_LACP_TIMEOUT)) port->sm_periodic_state = AD_SLOW_PERIODIC; // next state - } break; case AD_SLOW_PERIODIC: if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { @@ -1237,11 +1234,11 @@ static void ad_periodic_machine(struct port *port) port->sm_periodic_state = AD_FAST_PERIODIC; // next state break; case AD_PERIODIC_TX: - if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state + & AD_STATE_LACP_TIMEOUT)) port->sm_periodic_state = AD_SLOW_PERIODIC; // next state - } else { + else port->sm_periodic_state = AD_FAST_PERIODIC; // next state - } break; default: //to silence the compiler break; @@ -1287,35 +1284,37 @@ static void ad_port_selection_logic(struct port *port) int found = 0; // if the port is already Selected, do nothing - if (port->sm_vars & AD_PORT_SELECTED) { + if (port->sm_vars & AD_PORT_SELECTED) return; - } // if the port is connected to other aggregator, detach it if (port->aggregator) { // detach the port from its former aggregator - temp_aggregator=port->aggregator; - for (curr_port=temp_aggregator->lag_ports; curr_port; last_port=curr_port, curr_port=curr_port->next_port_in_aggregator) { + temp_aggregator = port->aggregator; + for (curr_port = temp_aggregator->lag_ports; curr_port; + last_port = curr_port, + curr_port = curr_port->next_port_in_aggregator) { if (curr_port == port) { temp_aggregator->num_of_ports--; if (!last_port) {// if it is the first port attached to the aggregator - temp_aggregator->lag_ports=port->next_port_in_aggregator; + temp_aggregator->lag_ports = + port->next_port_in_aggregator; } else {// not the first port attached to the aggregator - last_port->next_port_in_aggregator=port->next_port_in_aggregator; + last_port->next_port_in_aggregator = + port->next_port_in_aggregator; } // clear the port's relations to this aggregator port->aggregator = NULL; - port->next_port_in_aggregator=NULL; - port->actor_port_aggregator_identifier=0; + port->next_port_in_aggregator = NULL; + port->actor_port_aggregator_identifier = 0; pr_debug("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached - if (!temp_aggregator->lag_ports) { + if (!temp_aggregator->lag_ports) ad_clear_agg(temp_aggregator); - } break; } } @@ -1333,9 +1332,8 @@ static void ad_port_selection_logic(struct port *port) // keep a free aggregator for later use(if needed) if (!aggregator->lag_ports) { - if (!free_aggregator) { - free_aggregator=aggregator; - } + if (!free_aggregator) + free_aggregator = aggregator; continue; } // check if current aggregator suits us @@ -1350,10 +1348,11 @@ static void ad_port_selection_logic(struct port *port) ) { // attach to the founded aggregator port->aggregator = aggregator; - port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier; - port->next_port_in_aggregator=aggregator->lag_ports; + port->actor_port_aggregator_identifier = + port->aggregator->aggregator_identifier; + port->next_port_in_aggregator = aggregator->lag_ports; port->aggregator->num_of_ports++; - aggregator->lag_ports=port; + aggregator->lag_ports = port; pr_debug("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); @@ -1370,20 +1369,23 @@ static void ad_port_selection_logic(struct port *port) if (free_aggregator) { // assign port a new aggregator port->aggregator = free_aggregator; - port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier; + port->actor_port_aggregator_identifier = + port->aggregator->aggregator_identifier; // update the new aggregator's parameters // if port was responsed from the end-user - if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex + if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) + /* if port is full duplex */ port->aggregator->is_individual = false; - } else { + else port->aggregator->is_individual = true; - } port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system=port->partner_oper.system; - port->aggregator->partner_system_priority = port->partner_oper.system_priority; + port->aggregator->partner_system = + port->partner_oper.system; + port->aggregator->partner_system_priority = + port->partner_oper.system_priority; port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; port->aggregator->receive_state = 1; port->aggregator->transmit_state = 1; @@ -1704,9 +1706,8 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; port->actor_oper_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; - if (lacp_fast) { + if (lacp_fast) port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT; - } memcpy(&port->partner_admin, &tmpl, sizeof(tmpl)); memcpy(&port->partner_oper, &tmpl, sizeof(tmpl)); @@ -1785,13 +1786,16 @@ static void ad_marker_info_send(struct port *port) marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8)); marker.requester_system = port->actor_system; // convert requester_port(u32) to Big Endian - marker.requester_transaction_id = (((++port->transaction_id & 0xFF) << 24) |((port->transaction_id & 0xFF00) << 8) |((port->transaction_id & 0xFF0000) >> 8) |((port->transaction_id & 0xFF000000) >> 24)); + marker.requester_transaction_id = + (((++port->transaction_id & 0xFF) << 24) + | ((port->transaction_id & 0xFF00) << 8) + | ((port->transaction_id & 0xFF0000) >> 8) + | ((port->transaction_id & 0xFF000000) >> 24)); marker.pad = 0; marker.tlv_type_terminator = 0x00; marker.terminator_length = 0x00; - for (index=0; index<90; index++) { - marker.reserved_90[index]=0; - } + for (index = 0; index < 90; index++) + marker.reserved_90[index] = 0; // send the marker information if (ad_marker_send(port, &marker) >= 0) { @@ -1816,7 +1820,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info, //marker = *marker_info; memcpy(&marker, marker_info, sizeof(struct bond_marker)); // change the marker subtype to marker response - marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE; + marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE; // send the marker response if (ad_marker_send(port, &marker) >= 0) { @@ -1837,8 +1841,8 @@ static void ad_marker_info_received(struct bond_marker *marker_info, static void ad_marker_response_received(struct bond_marker *marker, struct port *port) { - marker=NULL; // just to satisfy the compiler - port=NULL; // just to satisfy the compiler + marker = NULL; /* just to satisfy the compiler */ + port = NULL; /* just to satisfy the compiler */ // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW } @@ -1932,9 +1936,8 @@ int bond_3ad_bind_slave(struct slave *slave) 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_BITS)) { + if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) port->sm_vars &= ~AD_PORT_LACP_ENABLED; - } // actor system is the bond's system port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; // tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second) @@ -2006,9 +2009,10 @@ void bond_3ad_unbind_slave(struct slave *slave) new_aggregator = __get_first_agg(port); for (; new_aggregator; new_aggregator = __get_next_agg(new_aggregator)) { // if the new aggregator is empty, or it is connected to our port only - if (!new_aggregator->lag_ports || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator)) { + if (!new_aggregator->lag_ports + || ((new_aggregator->lag_ports == port) + && !new_aggregator->lag_ports->next_port_in_aggregator)) break; - } } // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator @@ -2037,17 +2041,17 @@ void bond_3ad_unbind_slave(struct slave *slave) new_aggregator->num_of_ports = aggregator->num_of_ports; // update the information that is written on the ports about the aggregator - for (temp_port=aggregator->lag_ports; temp_port; temp_port=temp_port->next_port_in_aggregator) { - temp_port->aggregator=new_aggregator; + for (temp_port = aggregator->lag_ports; temp_port; + temp_port = temp_port->next_port_in_aggregator) { + temp_port->aggregator = new_aggregator; temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; } // clear the aggregator ad_clear_agg(aggregator); - if (select_new_active_agg) { + if (select_new_active_agg) ad_agg_selection_logic(__get_first_agg(port)); - } } else { pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n", slave->dev->master->name); @@ -2071,15 +2075,16 @@ void bond_3ad_unbind_slave(struct slave *slave) for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { prev_port = NULL; // search the port in the aggregator's related ports - for (temp_port=temp_aggregator->lag_ports; temp_port; prev_port=temp_port, temp_port=temp_port->next_port_in_aggregator) { + for (temp_port = temp_aggregator->lag_ports; temp_port; + prev_port = temp_port, + temp_port = temp_port->next_port_in_aggregator) { if (temp_port == port) { // the aggregator found - detach the port from this aggregator - if (prev_port) { + if (prev_port) prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator; - } else { + else temp_aggregator->lag_ports = temp_port->next_port_in_aggregator; - } temp_aggregator->num_of_ports--; - if (temp_aggregator->num_of_ports==0) { + if (temp_aggregator->num_of_ports == 0) { select_new_active_agg = temp_aggregator->is_active; // clear the aggregator ad_clear_agg(temp_aggregator); @@ -2094,7 +2099,7 @@ void bond_3ad_unbind_slave(struct slave *slave) } } } - port->slave=NULL; + port->slave = NULL; } /** @@ -2119,14 +2124,12 @@ void bond_3ad_state_machine_handler(struct work_struct *work) read_lock(&bond->lock); - if (bond->kill_timers) { + if (bond->kill_timers) goto out; - } //check if there are any slaves - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) goto re_arm; - } // check if agg_select_timer timer after initialize is timed out if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) { @@ -2159,9 +2162,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) ad_tx_machine(port); // turn off the BEGIN bit, since we already handled it - if (port->sm_vars & AD_PORT_BEGIN) { + if (port->sm_vars & AD_PORT_BEGIN) port->sm_vars &= ~AD_PORT_BEGIN; - } } re_arm: @@ -2245,7 +2247,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) } port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; - port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); + port->actor_oper_port_key = port->actor_admin_port_key |= + (__get_link_speed(port) << 1); pr_debug("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 @@ -2262,7 +2265,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) { struct port *port; - port=&(SLAVE_AD_INFO(slave).port); + port = &(SLAVE_AD_INFO(slave).port); // if slave is null, the whole port is not initialized if (!port->slave) { @@ -2272,7 +2275,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) } port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; - port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); + port->actor_oper_port_key = port->actor_admin_port_key |= + __get_duplex(port); pr_debug("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize @@ -2304,14 +2308,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) if (link == BOND_LINK_UP) { port->is_enabled = true; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; - port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); + port->actor_oper_port_key = port->actor_admin_port_key |= + __get_duplex(port); port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; - port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); + port->actor_oper_port_key = port->actor_admin_port_key |= + (__get_link_speed(port) << 1); } else { /* link has failed */ port->is_enabled = false; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; - port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS); + port->actor_oper_port_key = (port->actor_admin_port_key &= + ~AD_SPEED_KEY_BITS); } //BOND_PRINT_DBG(("Port %d changed link status to %s", port->actor_port_number, ((link == BOND_LINK_UP)?"UP":"DOWN"))); // there is no need to reselect a new aggregator, just signal the @@ -2394,9 +2401,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) */ read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n", @@ -2420,9 +2426,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) if (agg && (agg->aggregator_identifier == agg_id)) { slave_agg_no--; - if (slave_agg_no < 0) { + if (slave_agg_no < 0) break; - } } } @@ -2438,9 +2443,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) int slave_agg_id = 0; struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; - if (agg) { + if (agg) slave_agg_id = agg->aggregator_identifier; - } if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) { res = bond_dev_queue_xmit(bond, skb, slave->dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e953c6ad6e6..beb3b7cecd5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -76,6 +76,7 @@ #include <linux/if_vlan.h> #include <linux/if_bonding.h> #include <linux/jiffies.h> +#include <linux/preempt.h> #include <net/route.h> #include <net/net_namespace.h> #include <net/netns/generic.h> @@ -109,6 +110,7 @@ static char *arp_validate; static char *fail_over_mac; static int all_slaves_active = 0; static struct bond_params bonding_defaults; +static int resend_igmp = BOND_DEFAULT_RESEND_IGMP; module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); @@ -163,9 +165,15 @@ module_param(all_slaves_active, int, 0); MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface" "by setting active flag for all slaves. " "0 for never (default), 1 for always."); +module_param(resend_igmp, int, 0); +MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link failure"); /*----------------------------- Global variables ----------------------------*/ +#ifdef CONFIG_NET_POLL_CONTROLLER +cpumask_var_t netpoll_block_tx; +#endif + static const char * const version = DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -176,9 +184,6 @@ static int arp_ip_count; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; static int lacp_fast; -#ifdef CONFIG_NET_POLL_CONTROLLER -static int disable_netpoll = 1; -#endif const struct bond_parm_tbl bond_lacp_tbl[] = { { "slow", AD_LACP_SLOW}, @@ -307,6 +312,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); + block_netpoll_tx(); write_lock_bh(&bond->lock); list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { @@ -341,6 +347,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) out: write_unlock_bh(&bond->lock); + unblock_netpoll_tx(); return res; } @@ -446,11 +453,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) { struct netpoll *np = bond->dev->npinfo->netpoll; slave_dev->npinfo = bond->dev->npinfo; - np->real_dev = np->dev = skb->dev; slave_dev->priv_flags |= IFF_IN_NETPOLL; - netpoll_send_skb(np, skb); + netpoll_send_skb_on_dev(np, skb, slave_dev); slave_dev->priv_flags &= ~IFF_IN_NETPOLL; - np->dev = bond->dev; } else #endif dev_queue_xmit(skb); @@ -865,18 +870,13 @@ static void bond_mc_del(struct bonding *bond, void *addr) } -/* - * Retrieve the list of registered multicast addresses for the bonding - * device and retransmit an IGMP JOIN request to the current active - * slave. - */ -static void bond_resend_igmp_join_requests(struct bonding *bond) +static void __bond_resend_igmp_join_requests(struct net_device *dev) { struct in_device *in_dev; struct ip_mc_list *im; rcu_read_lock(); - in_dev = __in_dev_get_rcu(bond->dev); + in_dev = __in_dev_get_rcu(dev); if (in_dev) { for (im = in_dev->mc_list; im; im = im->next) ip_mc_rejoin_group(im); @@ -886,6 +886,44 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) } /* + * Retrieve the list of registered multicast addresses for the bonding + * device and retransmit an IGMP JOIN request to the current active + * slave. + */ +static void bond_resend_igmp_join_requests(struct bonding *bond) +{ + struct net_device *vlan_dev; + struct vlan_entry *vlan; + + read_lock(&bond->lock); + + /* rejoin all groups on bond device */ + __bond_resend_igmp_join_requests(bond->dev); + + /* rejoin all groups on vlan devices */ + if (bond->vlgrp) { + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + vlan_dev = vlan_group_get_device(bond->vlgrp, + vlan->vlan_id); + if (vlan_dev) + __bond_resend_igmp_join_requests(vlan_dev); + } + } + + if (--bond->igmp_retrans > 0) + queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); + + read_unlock(&bond->lock); +} + +static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) +{ + struct bonding *bond = container_of(work, struct bonding, + mcast_work.work); + bond_resend_igmp_join_requests(bond); +} + +/* * flush all members of flush->mc_list from device dev->mc_list */ static void bond_mc_list_flush(struct net_device *bond_dev, @@ -944,7 +982,6 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, netdev_for_each_mc_addr(ha, bond->dev) dev_mc_add(new_active->dev, ha->addr); - bond_resend_igmp_join_requests(bond); } } @@ -1180,9 +1217,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } } - /* resend IGMP joins since all were sent on curr_active_slave */ - if (bond->params.mode == BOND_MODE_ROUNDROBIN) { - bond_resend_igmp_join_requests(bond); + /* resend IGMP joins since active slave has changed or + * all were sent on curr_active_slave */ + if ((USES_PRIMARY(bond->params.mode) && new_active) || + bond->params.mode == BOND_MODE_ROUNDROBIN) { + bond->igmp_retrans = bond->params.resend_igmp; + queue_delayed_work(bond->wq, &bond->mcast_work, 0); } } @@ -1294,9 +1334,14 @@ static bool slaves_support_netpoll(struct net_device *bond_dev) static void bond_poll_controller(struct net_device *bond_dev) { - struct net_device *dev = bond_dev->npinfo->netpoll->real_dev; - if (dev != bond_dev) - netpoll_poll_dev(dev); + struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave; + int i; + + bond_for_each_slave(bond, slave, i) { + if (slave->dev && IS_UP(slave->dev)) + netpoll_poll_dev(slave->dev); + } } static void bond_netpoll_cleanup(struct net_device *bond_dev) @@ -1763,23 +1808,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); #ifdef CONFIG_NET_POLL_CONTROLLER - /* - * Netpoll and bonding is broken, make sure it is not initialized - * until it is fixed. - */ - if (disable_netpoll) { + if (slaves_support_netpoll(bond_dev)) { + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + if (bond_dev->npinfo) + slave_dev->npinfo = bond_dev->npinfo; + } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - } else { - if (slaves_support_netpoll(bond_dev)) { - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; - if (bond_dev->npinfo) - slave_dev->npinfo = bond_dev->npinfo; - } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { - bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - pr_info("New slave device %s does not support netpoll\n", - slave_dev->name); - pr_info("Disabling netpoll support for %s\n", bond_dev->name); - } + pr_info("New slave device %s does not support netpoll\n", + slave_dev->name); + pr_info("Disabling netpoll support for %s\n", bond_dev->name); } #endif read_unlock(&bond->lock); @@ -1851,6 +1888,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } + block_netpoll_tx(); netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE); write_lock_bh(&bond->lock); @@ -1860,6 +1898,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) pr_info("%s: %s not enslaved\n", bond_dev->name, slave_dev->name); write_unlock_bh(&bond->lock); + unblock_netpoll_tx(); return -EINVAL; } @@ -1953,6 +1992,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } write_unlock_bh(&bond->lock); + unblock_netpoll_tx(); /* must do this from outside any spinlocks */ bond_destroy_slave_symlinks(bond_dev, slave_dev); @@ -1983,10 +2023,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) #ifdef CONFIG_NET_POLL_CONTROLLER read_lock_bh(&bond->lock); - /* Make sure netpoll over stays disabled until fixed. */ - if (!disable_netpoll) - if (slaves_support_netpoll(bond_dev)) - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + if (slaves_support_netpoll(bond_dev)) + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; read_unlock_bh(&bond->lock); if (slave_dev->netdev_ops->ndo_netpoll_cleanup) slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev); @@ -2019,8 +2057,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) * First release a slave and than destroy the bond if no more slaves are left. * Must be under rtnl_lock when this function is called. */ -int bond_release_and_destroy(struct net_device *bond_dev, - struct net_device *slave_dev) +static int bond_release_and_destroy(struct net_device *bond_dev, + struct net_device *slave_dev) { struct bonding *bond = netdev_priv(bond_dev); int ret; @@ -2142,7 +2180,6 @@ static int bond_release_all(struct net_device *bond_dev) out: write_unlock_bh(&bond->lock); - return 0; } @@ -2191,9 +2228,11 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi (old_active) && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, new_active); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } else res = -EINVAL; @@ -2368,8 +2407,11 @@ static void bond_miimon_commit(struct bonding *bond) slave->state = BOND_STATE_BACKUP; } - pr_info("%s: link status definitely up for interface %s.\n", - bond->dev->name, slave->dev->name); + bond_update_speed_duplex(slave); + + pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n", + bond->dev->name, slave->dev->name, + slave->speed, slave->duplex ? "full" : "half"); /* notify ad that the link status has changed */ if (bond->params.mode == BOND_MODE_8023AD) @@ -2422,9 +2464,11 @@ static void bond_miimon_commit(struct bonding *bond) do_failover: ASSERT_RTNL(); + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } bond_set_carrier(bond); @@ -2867,11 +2911,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work) } if (do_failover) { + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } re_arm: @@ -3030,9 +3076,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) do_failover: ASSERT_RTNL(); + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } bond_set_carrier(bond); @@ -3312,6 +3360,8 @@ static void bond_info_show_slave(struct seq_file *seq, seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); + seq_printf(seq, "Speed: %d Mbps\n", slave->speed); + seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half"); seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); @@ -3744,6 +3794,8 @@ static int bond_open(struct net_device *bond_dev) bond->kill_timers = 0; + INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed); + if (bond_is_lb(bond)) { /* bond_alb_initialize must be called before the timer * is started. @@ -3828,6 +3880,8 @@ static int bond_close(struct net_device *bond_dev) break; } + if (delayed_work_pending(&bond->mcast_work)) + cancel_delayed_work(&bond->mcast_work); if (bond_is_lb(bond)) { /* Must be called only after all @@ -4514,6 +4568,13 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = netdev_priv(dev); + /* + * If we risk deadlock from transmitting this in the + * netpoll path, tell netpoll to queue the frame for later tx + */ + if (is_netpoll_tx_blocked(dev)) + return NETDEV_TX_BUSY; + if (TX_QUEUE_OVERRIDE(bond->params.mode)) { if (!bond_slave_override(bond, skb)) return NETDEV_TX_OK; @@ -4678,6 +4739,10 @@ static void bond_setup(struct net_device *bond_dev) 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; } static void bond_work_cancel_all(struct bonding *bond) @@ -4699,6 +4764,9 @@ static void bond_work_cancel_all(struct bonding *bond) if (bond->params.mode == BOND_MODE_8023AD && delayed_work_pending(&bond->ad_work)) cancel_delayed_work(&bond->ad_work); + + if (delayed_work_pending(&bond->mcast_work)) + cancel_delayed_work(&bond->mcast_work); } /* @@ -4891,6 +4959,13 @@ static int bond_check_params(struct bond_params *params) all_slaves_active = 0; } + if (resend_igmp < 0 || resend_igmp > 255) { + pr_warning("Warning: resend_igmp (%d) should be between " + "0 and 255, resetting to %d\n", + resend_igmp, BOND_DEFAULT_RESEND_IGMP); + resend_igmp = BOND_DEFAULT_RESEND_IGMP; + } + /* reset values for TLB/ALB */ if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { @@ -5063,6 +5138,7 @@ static int bond_check_params(struct bond_params *params) params->fail_over_mac = fail_over_mac_value; params->tx_queues = tx_queues; params->all_slaves_active = all_slaves_active; + params->resend_igmp = resend_igmp; if (primary) { strncpy(params->primary, primary, IFNAMSIZ); @@ -5221,6 +5297,13 @@ static int __init bonding_init(void) if (res) goto out; +#ifdef CONFIG_NET_POLL_CONTROLLER + if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) { + res = -ENOMEM; + goto out; + } +#endif + res = register_pernet_subsys(&bond_net_ops); if (res) goto out; @@ -5239,6 +5322,7 @@ static int __init bonding_init(void) if (res) goto err; + register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); bond_register_ipv6_notifier(); @@ -5248,6 +5332,9 @@ err: rtnl_link_unregister(&bond_link_ops); err_link: unregister_pernet_subsys(&bond_net_ops); +#ifdef CONFIG_NET_POLL_CONTROLLER + free_cpumask_var(netpoll_block_tx); +#endif goto out; } @@ -5262,6 +5349,10 @@ static void __exit bonding_exit(void) rtnl_link_unregister(&bond_link_ops); unregister_pernet_subsys(&bond_net_ops); + +#ifdef CONFIG_NET_POLL_CONTROLLER + free_cpumask_var(netpoll_block_tx); +#endif } module_init(bonding_init); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index c311aed9bd0..8fd0174c538 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1066,6 +1066,7 @@ static ssize_t bonding_store_primary(struct device *d, if (!rtnl_trylock()) return restart_syscall(); + block_netpoll_tx(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); @@ -1101,6 +1102,7 @@ static ssize_t bonding_store_primary(struct device *d, out: write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + unblock_netpoll_tx(); rtnl_unlock(); return count; @@ -1146,11 +1148,13 @@ static ssize_t bonding_store_primary_reselect(struct device *d, bond->dev->name, pri_reselect_tbl[new_value].modename, new_value); + block_netpoll_tx(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + unblock_netpoll_tx(); out: rtnl_unlock(); return ret; @@ -1232,6 +1236,8 @@ static ssize_t bonding_store_active_slave(struct device *d, if (!rtnl_trylock()) return restart_syscall(); + + block_netpoll_tx(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); @@ -1288,6 +1294,8 @@ static ssize_t bonding_store_active_slave(struct device *d, out: write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + unblock_netpoll_tx(); + rtnl_unlock(); return count; @@ -1592,6 +1600,49 @@ out: static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, bonding_show_slaves_active, bonding_store_slaves_active); +/* + * Show and set the number of IGMP membership reports to send on link failure + */ +static ssize_t bonding_show_resend_igmp(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.resend_igmp); +} + +static ssize_t bonding_store_resend_igmp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (sscanf(buf, "%d", &new_value) != 1) { + pr_err("%s: no resend_igmp value specified.\n", + bond->dev->name); + ret = -EINVAL; + goto out; + } + + if (new_value < 0) { + pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n", + bond->dev->name, new_value); + ret = -EINVAL; + goto out; + } + + pr_info("%s: Setting resend_igmp to %d.\n", + bond->dev->name, new_value); + bond->params.resend_igmp = new_value; +out: + return ret; +} + +static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR, + bonding_show_resend_igmp, bonding_store_resend_igmp); + static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, @@ -1619,6 +1670,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_ad_partner_mac.attr, &dev_attr_queue_id.attr, &dev_attr_all_slaves_active.attr, + &dev_attr_resend_igmp.attr, NULL, }; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index c6fdd851579..4eedb12df6c 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -19,6 +19,7 @@ #include <linux/proc_fs.h> #include <linux/if_bonding.h> #include <linux/kobject.h> +#include <linux/cpumask.h> #include <linux/in6.h> #include "bond_3ad.h" #include "bond_alb.h" @@ -117,6 +118,35 @@ bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) +#ifdef CONFIG_NET_POLL_CONTROLLER +extern cpumask_var_t netpoll_block_tx; + +static inline void block_netpoll_tx(void) +{ + preempt_disable(); + BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(), + netpoll_block_tx)); +} + +static inline void unblock_netpoll_tx(void) +{ + BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(), + netpoll_block_tx)); + preempt_enable(); +} + +static inline int is_netpoll_tx_blocked(struct net_device *dev) +{ + if (unlikely(dev->priv_flags & IFF_IN_NETPOLL)) + return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx); + return 0; +} +#else +#define block_netpoll_tx() +#define unblock_netpoll_tx() +#define is_netpoll_tx_blocked(dev) (0) +#endif + struct bond_params { int mode; int xmit_policy; @@ -136,6 +166,7 @@ struct bond_params { __be32 arp_targets[BOND_MAX_ARP_TARGETS]; int tx_queues; int all_slaves_active; + int resend_igmp; }; struct bond_parm_tbl { @@ -202,6 +233,7 @@ struct bonding { s8 send_grat_arp; s8 send_unsol_na; s8 setup_by_slave; + s8 igmp_retrans; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; char proc_file_name[IFNAMSIZ]; @@ -223,6 +255,7 @@ struct bonding { struct delayed_work arp_work; struct delayed_work alb_work; struct delayed_work ad_work; + struct delayed_work mcast_work; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct in6_addr master_ipv6; #endif @@ -331,7 +364,6 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_create(struct net *net, const char *name); -int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_create_sysfs(void); void bond_destroy_sysfs(void); void bond_prepare_sysfs_group(struct bonding *bond); |