📄 bond_3ad.c
字号:
port->sm_vars |= AD_PORT_SELECTED; dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } // if all aggregator's ports are READY_N == TRUE, set ready=TRUE in all aggregator's ports // else set ready=FALSE in all aggregator's ports __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) { ad_agg_selection_logic(aggregator); }}/** * ad_agg_selection_logic - select an aggregation group for a team * @aggregator: the aggregator we're looking at * * It is assumed that only one aggregator may be selected for a team. * The logic of this function is to select (at first time) the aggregator with * the most ports attached to it, and to reselect the active aggregator only if * the previous aggregator has no more ports related to it. * * FIXME: this function MUST be called with the first agg in the bond, or * __get_active_agg() won't work correctly. This function should be better * called with the bond itself, and retrieve the first agg from it. */static void ad_agg_selection_logic(struct aggregator *aggregator){ struct aggregator *best_aggregator = NULL, *active_aggregator = NULL; struct aggregator *last_active_aggregator = NULL, *origin_aggregator; struct port *port; u16 num_of_aggs=0; origin_aggregator = aggregator; //get current active aggregator last_active_aggregator = __get_active_agg(aggregator); // search for the aggregator with the most ports attached to it. do { // count how many candidate lag's we have if (aggregator->lag_ports) { num_of_aggs++; } if (aggregator->is_active && !aggregator->is_individual && // if current aggregator is the active aggregator MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) { // and partner answers to 802.3ad PDUs if (aggregator->num_of_ports) { // if any ports attached to the current aggregator best_aggregator=NULL; // disregard the best aggregator that was chosen by now break; // stop the selection of other aggregator if there are any ports attached to this active aggregator } else { // no ports attached to this active aggregator aggregator->is_active = 0; // mark this aggregator as not active anymore } } if (aggregator->num_of_ports) { // if any ports attached if (best_aggregator) { // if there is a candidte aggregator //The reasons for choosing new best aggregator: // 1. if current agg is NOT individual and the best agg chosen so far is individual OR // current and best aggs are both individual or both not individual, AND // 2a. current agg partner reply but best agg partner do not reply OR // 2b. current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND // current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN // current agg become best agg so far //if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator if (!aggregator->is_individual && best_aggregator->is_individual) { best_aggregator=aggregator; } // current and best aggs are both individual or both not individual else if ((aggregator->is_individual && best_aggregator->is_individual) || (!aggregator->is_individual && !best_aggregator->is_individual)) { // current and best aggs are both individual or both not individual AND // current agg partner reply but best agg partner do not reply if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { best_aggregator=aggregator; } // current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&& (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) { best_aggregator=aggregator; } else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) { if (((aggregator->num_of_ports > best_aggregator->num_of_ports) && (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))|| ((aggregator->num_of_ports == best_aggregator->num_of_ports) && ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) > (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) { best_aggregator=aggregator; } } } } } else { best_aggregator=aggregator; } } aggregator->is_active = 0; // mark all aggregators as not active anymore } while ((aggregator = __get_next_agg(aggregator))); // if we have new aggregator selected, don't replace the old aggregator if it has an answering partner, // or if both old aggregator and new aggregator don't have answering partner if (best_aggregator) { if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled && (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) || // partner answers OR (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) && // both old and new !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) // partner do not answer ) { // if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing) // -> don't replace otherwise. if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) { best_aggregator=NULL; last_active_aggregator->is_active = 1; // don't replace good old aggregator } } } // if there is new best aggregator, activate it if (best_aggregator) { for (aggregator = __get_first_agg(best_aggregator->lag_ports); aggregator; aggregator = __get_next_agg(aggregator)) { dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", aggregator->aggregator_identifier, aggregator->num_of_ports, aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, aggregator->is_individual, aggregator->is_active); } // check if any partner replys if (best_aggregator->is_individual) { printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner " "for any adapters in the bond\n"); } // check if there are more than one aggregator if (num_of_aggs > 1) { dprintk("Warning: More than one Link Aggregation Group was " "found in the bond. Only one group will function in the bond\n"); } best_aggregator->is_active = 1; dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, best_aggregator->is_individual, best_aggregator->is_active); // disable the ports that were related to the former active_aggregator if (last_active_aggregator) { for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { __disable_port(port); } } } // if the selected aggregator is of join individuals(partner_system is NULL), enable their ports active_aggregator = __get_active_agg(origin_aggregator); if (active_aggregator) { if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) { for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { __enable_port(port); } } }}/** * ad_clear_agg - clear a given aggregator's parameters * @aggregator: the aggregator we're looking at * */static void ad_clear_agg(struct aggregator *aggregator){ if (aggregator) { aggregator->is_individual = 0; aggregator->actor_admin_aggregator_key = 0; aggregator->actor_oper_aggregator_key = 0; aggregator->partner_system = null_mac_addr; aggregator->partner_system_priority = 0; aggregator->partner_oper_aggregator_key = 0; aggregator->receive_state = 0; aggregator->transmit_state = 0; aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); }}/** * ad_initialize_agg - initialize a given aggregator's parameters * @aggregator: the aggregator we're looking at * */static void ad_initialize_agg(struct aggregator *aggregator){ if (aggregator) { ad_clear_agg(aggregator); aggregator->aggregator_mac_address = null_mac_addr; aggregator->aggregator_identifier = 0; aggregator->slave = NULL; }}/** * ad_initialize_port - initialize a given port's parameters * @aggregator: the aggregator we're looking at * @lacp_fast: boolean. whether fast periodic should be used * */static void ad_initialize_port(struct port *port, int lacp_fast){ if (port) { port->actor_port_number = 1; port->actor_port_priority = 0xff; port->actor_system = null_mac_addr; port->actor_system_priority = 0xffff; port->actor_port_aggregator_identifier = 0; port->ntt = 0; port->actor_admin_port_key = 1; port->actor_oper_port_key = 1; 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) { port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT; } port->partner_admin_system = null_mac_addr; port->partner_oper_system = null_mac_addr; port->partner_admin_system_priority = 0xffff; port->partner_oper_system_priority = 0xffff; port->partner_admin_key = 1; port->partner_oper_key = 1; port->partner_admin_port_number = 1; port->partner_oper_port_number = 1; port->partner_admin_port_priority = 0xff; port->partner_oper_port_priority = 0xff; port->partner_admin_port_state = 1; port->partner_oper_port_state = 1; port->is_enabled = 1; // ****** private parameters ****** port->sm_vars = 0x3; port->sm_rx_state = 0; port->sm_rx_timer_counter = 0; port->sm_periodic_state = 0; port->sm_periodic_timer_counter = 0; port->sm_mux_state = 0; port->sm_mux_timer_counter = 0; port->sm_tx_state = 0; port->sm_tx_timer_counter = 0; port->slave = NULL; port->aggregator = NULL; port->next_port_in_aggregator = NULL; port->transaction_id = 0; ad_initialize_lacpdu(&(port->lacpdu)); }}/** * ad_enable_collecting_distributing - enable a port's transmit/receive * @port: the port we're looking at * * Enable @port if it's in an active aggregator */static void ad_enable_collecting_distributing(struct port *port){ if (port->aggregator->is_active) { dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); }}/** * ad_disable_collecting_distributing - disable a port's transmit/receive * @port: the port we're looking at * */static void ad_disable_collecting_distributing(struct port *port){ if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); }}#if 0/** * ad_marker_info_send - send a marker information frame * @port: the port we're looking at * * This function does nothing since we decided not to implement send and handle * response for marker PDU's, in this stage, but only to respond to marker * information. */static void ad_marker_info_send(struct port *port){ struct marker marker; u16 index; // fill the marker PDU with the appropriate values marker.subtype = 0x02; marker.version_number = 0x01; marker.tlv_type = AD_MARKER_INFORMATION_SUBTYPE; marker.marker_length = 0x16; // convert requester_port to Big Endian 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.pad = 0; marker.tlv_type_terminator = 0x00; marker.terminator_length = 0x00; for (index=0; index<90; index++) { marker.reserved_90[index]=0; } // send the marker information if (ad_marker_send(port, &marker) >= 0) { dprintk("Sent Marker Information on port %d\n", port->actor_port_number); }}#endif/** * ad_marker_info_received - handle receive of a Marker information frame * @marker_info: Marker info received * @port: the port we're looking at * */static void ad_marker_info_received(struct marker *marker_info,struct port *port){ struct marker marker; // copy the received marker data to the response marker //marker = *marker_info; memcpy(&marker, marker_info, sizeof(struct marker)); // change the marker subtype to marker response marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE; // send the marker response if (ad_marker_send(port, &marker) >= 0) { dprintk("Sent Marker Response on port %d\n", port->actor_port_number); }}/** * ad_marker_response_received - handle receive of a marker response frame * @marker: marker PDU received * @port: the por
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -