📄 bond_3ad.c
字号:
}/** * ad_rx_machine - handle a port's rx State Machine * @lacpdu: the lacpdu we've received * @port: the port we're looking at * * If lacpdu arrived, stop previous timer (if exists) and set the next state as * CURRENT. If timer expired set the state machine in the proper state. * In other cases, this function checks if we need to switch to other state. */static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port){ rx_states_t last_state; // Lock to prevent 2 instances of this function to run simultaneously(rx interrupt and periodic machine callback) __get_rx_machine_lock(port); // keep current State Machine state to compare later if it was changed last_state = port->sm_rx_state; // 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 } // 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 } // 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 port->sm_rx_state = AD_RX_CURRENT; } else { // if timer is on, and if it is expired if (port->sm_rx_timer_counter && !(--port->sm_rx_timer_counter)) { switch (port->sm_rx_state) { case AD_RX_EXPIRED: port->sm_rx_state = AD_RX_DEFAULTED; // next state break; case AD_RX_CURRENT: port->sm_rx_state = AD_RX_EXPIRED; // next state break; default: //to silence the compiler break; } } else { // 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) { port->sm_rx_state = AD_RX_INITIALIZE; // next state } 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)) { port->sm_rx_state = AD_RX_LACP_DISABLED; // next state } break; default: //to silence the compiler break; } } } // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { port->sm_vars &= ~AD_PORT_LACP_ENABLED; } 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; port->sm_vars &= ~AD_PORT_MOVED; port->sm_rx_state = AD_RX_PORT_DISABLED; // next state /*- Fall Through -*/ case AD_RX_PORT_DISABLED: port->sm_vars &= ~AD_PORT_MATCHED; break; case AD_RX_LACP_DISABLED: port->sm_vars &= ~AD_PORT_SELECTED; __record_default(port); port->partner_oper_port_state &= ~AD_STATE_AGGREGATION; port->sm_vars |= AD_PORT_MATCHED; port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; case AD_RX_EXPIRED: //Reset of the Synchronization flag. (Standard 43.4.12) //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; port->partner_oper_port_state |= AD_SHORT_TIMEOUT; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; case AD_RX_DEFAULTED: __update_default_selected(port); __record_default(port); port->sm_vars |= AD_PORT_MATCHED; port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; case AD_RX_CURRENT: // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n", port->slave->dev->name); printk(KERN_ERR "Check the configuration to verify that all Adapters " "are connected to 802.3ad compliant switch ports\n"); __release_rx_machine_lock(port); return; } __update_selected(lacpdu, port); __update_ntt(lacpdu, port); __record_pdu(lacpdu, port); __choose_matched(lacpdu, port); port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)); port->actor_oper_port_state &= ~AD_STATE_EXPIRED; // 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)) { __enable_port(port); } break; default: //to silence the compiler break; } } __release_rx_machine_lock(port);}/** * ad_tx_machine - handle a port's tx state machine * @port: the port we're looking at * */static void ad_tx_machine(struct port *port){ // check if tx timer expired, to verify that we do not send more than 3 packets per second if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) { // check if there is something to send if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) { __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { dprintk("Sent LACPDU on port %d\n", port->actor_port_number); // mark ntt as false, so it will not be sent again until demanded port->ntt = 0; } } // 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; }}/** * ad_periodic_machine - handle a port's periodic state machine * @port: the port we're looking at * * Turn ntt flag on priodically to perform periodic transmission of lacpdu's. */static void ad_periodic_machine(struct port *port){ periodic_states_t last_state; // keep current state machine state to compare later if it was changed last_state = port->sm_periodic_state; // check if port was reinitialized if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) || (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY)) ) { port->sm_periodic_state = AD_NO_PERIODIC; // next state } // check if state machine should change state else if (port->sm_periodic_timer_counter) { // check if periodic state machine expired if (!(--port->sm_periodic_timer_counter)) { // if expired then do tx port->sm_periodic_state = AD_PERIODIC_TX; // next state } else { // 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)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } break; case AD_SLOW_PERIODIC: if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { // stop current timer port->sm_periodic_timer_counter = 0; port->sm_periodic_state = AD_PERIODIC_TX; // next state } break; default: //to silence the compiler break; } } } else { switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_state = AD_FAST_PERIODIC; // next state break; case AD_PERIODIC_TX: if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } else { port->sm_periodic_state = AD_FAST_PERIODIC; // next state } break; default: //to silence the compiler break; } } // check if the state machine was changed if (port->sm_periodic_state != last_state) { dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer break; case AD_FAST_PERIODIC: port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle break; case AD_SLOW_PERIODIC: port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle break; case AD_PERIODIC_TX: port->ntt = 1; break; default: //to silence the compiler break; } }}/** * ad_port_selection_logic - select aggregation groups * @port: the port we're looking at * * Select aggregation groups, and assign each port for it's aggregetor. The * selection logic is called in the inititalization (after all the handshkes), * and after every lacpdu receive (if selected is off). */static void ad_port_selection_logic(struct port *port){ struct aggregator *aggregator, *free_aggregator = NULL, *temp_aggregator; struct port *last_port = NULL, *curr_port; int found = 0; // if the port is already Selected, do nothing 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) { 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; } else {// not the first port attached to the 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; dprintk("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) { ad_clear_agg(temp_aggregator); } break; } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was " "related to aggregator %d but was not on its port list\n", port->actor_port_number, port->slave->dev->name, port->aggregator->aggregator_identifier); } } // search on all aggregators for a suitable aggregator for this port for (aggregator = __get_first_agg(port); aggregator; aggregator = __get_next_agg(aggregator)) { // keep a free aggregator for later use(if needed) if (!aggregator->lag_ports) { if (!free_aggregator) { free_aggregator=aggregator; } continue; } // check if current aggregator suits us if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) && (aggregator->partner_system_priority == port->partner_oper_system_priority) && (aggregator->partner_oper_aggregator_key == port->partner_oper_key) ) && ((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers !aggregator->is_individual) // but is not individual OR ) ) { // 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->aggregator->num_of_ports++; aggregator->lag_ports=port; dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; found = 1; break; } } // the port couldn't find an aggregator - attach it to a new aggregator if (!found) { if (free_aggregator) { // assign port a new aggregator port->aggregator = free_aggregator; 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 port->aggregator->is_individual = 0; } else { port->aggregator->is_individual = 1; } 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_oper_aggregator_key = port->partner_oper_key; port->aggregator->receive_state = 1; port->aggregator->transmit_state = 1; port->aggregator->lag_ports = port; port->aggregator->num_of_ports++; // mark this port as selected
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -