⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bond_3ad.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
}/** * 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 + -