📄 bond_3ad.c
字号:
/* * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * * Changes: * * 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and * Amir Noam <amir.noam at intel dot com> * - Added support for lacp_rate module param. * * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> * - Based on discussion on mailing list, changed locking scheme * to use lock/unlock or lock_bh/unlock_bh appropriately instead * of lock_irqsave/unlock_irqrestore. The new scheme helps exposing * hidden bugs and solves system hangs that occurred due to the fact * that holding lock_irqsave doesn't prevent softirqs from running. * This also increases total throughput since interrupts are not * blocked on each transmitted packets or monitor timeout. * * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. * * 2003/05/20 - Amir Noam <amir.noam at intel dot com> * - Fix long fail over time when releasing last slave of an active * aggregator - send LACPDU on unbind of slave to tell partner this * port is no longer aggregatable. * * 2003/06/25 - Tsippy Mendelson <tsippy.mendelson at intel dot com> * - Send LACPDU as highest priority packet to further fix the above * problem on very high Tx traffic load where packets may get dropped * by the slave. * * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com> * - Code cleanup and style changes *///#define BONDING_DEBUG 1#include <linux/skbuff.h>#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/spinlock.h>#include <linux/ethtool.h>#include <linux/if_bonding.h>#include <linux/pkt_sched.h>#include "bonding.h"#include "bond_3ad.h"// General definitions#define AD_SHORT_TIMEOUT 1#define AD_LONG_TIMEOUT 0#define AD_STANDBY 0x2#define AD_MAX_TX_IN_SECOND 3#define AD_COLLECTOR_MAX_DELAY 0// Timer definitions(43.4.4 in the 802.3ad standard)#define AD_FAST_PERIODIC_TIME 1#define AD_SLOW_PERIODIC_TIME 30#define AD_SHORT_TIMEOUT_TIME (3*AD_FAST_PERIODIC_TIME)#define AD_LONG_TIMEOUT_TIME (3*AD_SLOW_PERIODIC_TIME)#define AD_CHURN_DETECTION_TIME 60#define AD_AGGREGATE_WAIT_TIME 2// Port state definitions(43.4.2.2 in the 802.3ad standard)#define AD_STATE_LACP_ACTIVITY 0x1#define AD_STATE_LACP_TIMEOUT 0x2#define AD_STATE_AGGREGATION 0x4#define AD_STATE_SYNCHRONIZATION 0x8#define AD_STATE_COLLECTING 0x10#define AD_STATE_DISTRIBUTING 0x20#define AD_STATE_DEFAULTED 0x40#define AD_STATE_EXPIRED 0x80// Port Variables definitions used by the State Machines(43.4.7 in the 802.3ad standard)#define AD_PORT_BEGIN 0x1#define AD_PORT_LACP_ENABLED 0x2#define AD_PORT_ACTOR_CHURN 0x4#define AD_PORT_PARTNER_CHURN 0x8#define AD_PORT_READY 0x10#define AD_PORT_READY_N 0x20#define AD_PORT_MATCHED 0x40#define AD_PORT_STANDBY 0x80#define AD_PORT_SELECTED 0x100#define AD_PORT_MOVED 0x200// Port Key definitions// key is determined according to the link speed, duplex and// user key(which is yet not supported)// ------------------------------------------------------------// Port key : | User key | Speed |Duplex|// ------------------------------------------------------------// 16 6 1 0#define AD_DUPLEX_KEY_BITS 0x1#define AD_SPEED_KEY_BITS 0x3E#define AD_USER_KEY_BITS 0xFFC0//dalloun#define AD_LINK_SPEED_BITMASK_1MBPS 0x1#define AD_LINK_SPEED_BITMASK_10MBPS 0x2#define AD_LINK_SPEED_BITMASK_100MBPS 0x4#define AD_LINK_SPEED_BITMASK_1000MBPS 0x8//endalloun// 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 u16 ad_ticks_per_sec;static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;// ================= 3AD api to bonding and kernel code ==================static u16 __get_link_speed(struct port *port);static u8 __get_duplex(struct port *port);static inline void __initialize_port_locks(struct port *port);//conversionsstatic void __ntohs_lacpdu(struct lacpdu *lacpdu);static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);// ================= ad code helper functions ==================//needed by ad_rx_machine(...)static void __record_pdu(struct lacpdu *lacpdu, struct port *port);static void __record_default(struct port *port);static void __update_selected(struct lacpdu *lacpdu, struct port *port);static void __update_default_selected(struct port *port);static void __choose_matched(struct lacpdu *lacpdu, struct port *port);static void __update_ntt(struct lacpdu *lacpdu, struct port *port);//needed for ad_mux_machine(..)static void __attach_bond_to_agg(struct port *port);static void __detach_bond_from_agg(struct port *port);static int __agg_ports_are_ready(struct aggregator *aggregator);static void __set_agg_ports_ready(struct aggregator *aggregator, int val);//needed for ad_agg_selection_logic(...)static u32 __get_agg_bandwidth(struct aggregator *aggregator);static struct aggregator *__get_active_agg(struct aggregator *aggregator);// ================= main 802.3ad protocol functions ==================static int ad_lacpdu_send(struct port *port);static int ad_marker_send(struct port *port, struct marker *marker);static void ad_mux_machine(struct port *port);static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);static void ad_tx_machine(struct port *port);static void ad_periodic_machine(struct port *port);static void ad_port_selection_logic(struct port *port);static void ad_agg_selection_logic(struct aggregator *aggregator);static void ad_clear_agg(struct aggregator *aggregator);static void ad_initialize_agg(struct aggregator *aggregator);static void ad_initialize_port(struct port *port, int lacp_fast);static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);static void ad_enable_collecting_distributing(struct port *port);static void ad_disable_collecting_distributing(struct port *port);static void ad_marker_info_received(struct marker *marker_info, struct port *port);static void ad_marker_response_received(struct marker *marker, struct port *port);/////////////////////////////////////////////////////////////////////////////////// ================= api to bonding and kernel code ==================//////////////////////////////////////////////////////////////////////////////////** * __get_bond_by_port - get the port's bonding struct * @port: the port we're looking at * * Return @port's bonding struct, or %NULL if it can't be found. */static inline struct bonding *__get_bond_by_port(struct port *port){ if (port->slave == NULL) { return NULL; } return bond_get_bond_by_slave(port->slave);}/** * __get_first_port - get the first port in the bond * @bond: the bond we're looking at * * Return the port of the first slave in @bond, or %NULL if it can't be found. */static inline struct port *__get_first_port(struct bonding *bond){ if (bond->slave_cnt == 0) { return NULL; } return &(SLAVE_AD_INFO(bond->first_slave).port);}/** * __get_next_port - get the next port in the bond * @port: the port we're looking at * * Return the port of the slave that is next in line of @port's slave in the * bond, or %NULL if it can't be found. */static inline struct port *__get_next_port(struct port *port){ struct bonding *bond = __get_bond_by_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)) { return NULL; } return &(SLAVE_AD_INFO(slave->next).port);}/** * __get_first_agg - get the first aggregator in the bond * @bond: the bond we're looking at * * Return the aggregator of the first slave in @bond, or %NULL if it can't be * found. */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)) { return NULL; } return &(SLAVE_AD_INFO(bond->first_slave).aggregator);}/** * __get_next_agg - get the next aggregator in the bond * @aggregator: the aggregator we're looking at * * Return the aggregator of the slave that is next in line of @aggregator's * slave in the bond, or %NULL if it can't be found. */static inline struct aggregator *__get_next_agg(struct aggregator *aggregator){ struct slave *slave = aggregator->slave; 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)) { return NULL; } return &(SLAVE_AD_INFO(slave->next).aggregator);}/** * __disable_port - disable the port's slave * @port: the port we're looking at * */static inline void __disable_port(struct port *port){ bond_set_slave_inactive_flags(port->slave);}/** * __enable_port - enable the port's slave, if it's up * @port: the port we're looking at * */static inline void __enable_port(struct port *port){ struct slave *slave = port->slave; if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) { bond_set_slave_active_flags(slave); }}/** * __port_is_enabled - check if the port's slave is in active state * @port: the port we're looking at * */static inline int __port_is_enabled(struct port *port){ return(port->slave->state == BOND_STATE_ACTIVE);}/** * __get_agg_selection_mode - get the aggregator selection mode * @port: the port we're looking at * * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT. */static inline u32 __get_agg_selection_mode(struct port *port){ struct bonding *bond = __get_bond_by_port(port); if (bond == NULL) { return AD_BANDWIDTH; } return BOND_AD_INFO(bond).agg_select_mode;}/** * __check_agg_selection_timer - check if the selection timer has expired * @port: the port we're looking at * */static inline int __check_agg_selection_timer(struct port *port){ struct bonding *bond = __get_bond_by_port(port); if (bond == NULL) { return 0; } return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;}/** * __get_rx_machine_lock - lock the port's RX machine * @port: the port we're looking at * */static inline void __get_rx_machine_lock(struct port *port){ spin_lock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));}/** * __release_rx_machine_lock - unlock the port's RX machine * @port: the port we're looking at * */static inline void __release_rx_machine_lock(struct port *port){ spin_unlock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));}/** * __get_link_speed - get a port's speed * @port: the port we're looking at * * Return @port's speed in 802.3ad bitmask format. i.e. one of: * 0,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -