19e567af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds #include <linux/skbuff.h>
71da177e4SLinus Torvalds #include <linux/if_ether.h>
81da177e4SLinus Torvalds #include <linux/netdevice.h>
91da177e4SLinus Torvalds #include <linux/spinlock.h>
101da177e4SLinus Torvalds #include <linux/ethtool.h>
11fd989c83SJay Vosburgh #include <linux/etherdevice.h>
121da177e4SLinus Torvalds #include <linux/if_bonding.h>
131da177e4SLinus Torvalds #include <linux/pkt_sched.h>
14e730c155SEric W. Biederman #include <net/net_namespace.h>
151ef8019bSDavid S. Miller #include <net/bonding.h>
161ef8019bSDavid S. Miller #include <net/bond_3ad.h>
17a258aeacSNikolay Aleksandrov #include <net/netlink.h>
181da177e4SLinus Torvalds
193bf2d28aSVeaceslav Falico /* General definitions */
201da177e4SLinus Torvalds #define AD_SHORT_TIMEOUT 1
211da177e4SLinus Torvalds #define AD_LONG_TIMEOUT 0
221da177e4SLinus Torvalds #define AD_STANDBY 0x2
231da177e4SLinus Torvalds #define AD_MAX_TX_IN_SECOND 3
241da177e4SLinus Torvalds #define AD_COLLECTOR_MAX_DELAY 0
251da177e4SLinus Torvalds
263bf2d28aSVeaceslav Falico /* Timer definitions (43.4.4 in the 802.3ad standard) */
271da177e4SLinus Torvalds #define AD_FAST_PERIODIC_TIME 1
281da177e4SLinus Torvalds #define AD_SLOW_PERIODIC_TIME 30
291da177e4SLinus Torvalds #define AD_SHORT_TIMEOUT_TIME (3*AD_FAST_PERIODIC_TIME)
301da177e4SLinus Torvalds #define AD_LONG_TIMEOUT_TIME (3*AD_SLOW_PERIODIC_TIME)
311da177e4SLinus Torvalds #define AD_CHURN_DETECTION_TIME 60
321da177e4SLinus Torvalds #define AD_AGGREGATE_WAIT_TIME 2
331da177e4SLinus Torvalds
343bf2d28aSVeaceslav Falico /* Port Variables definitions used by the State Machines (43.4.7 in the
353bf2d28aSVeaceslav Falico * 802.3ad standard)
363bf2d28aSVeaceslav Falico */
371da177e4SLinus Torvalds #define AD_PORT_BEGIN 0x1
381da177e4SLinus Torvalds #define AD_PORT_LACP_ENABLED 0x2
391da177e4SLinus Torvalds #define AD_PORT_ACTOR_CHURN 0x4
401da177e4SLinus Torvalds #define AD_PORT_PARTNER_CHURN 0x8
411da177e4SLinus Torvalds #define AD_PORT_READY 0x10
421da177e4SLinus Torvalds #define AD_PORT_READY_N 0x20
431da177e4SLinus Torvalds #define AD_PORT_MATCHED 0x40
441da177e4SLinus Torvalds #define AD_PORT_STANDBY 0x80
451da177e4SLinus Torvalds #define AD_PORT_SELECTED 0x100
461da177e4SLinus Torvalds #define AD_PORT_MOVED 0x200
47ef015d72SMahesh Bandewar #define AD_PORT_CHURNED (AD_PORT_ACTOR_CHURN | AD_PORT_PARTNER_CHURN)
481da177e4SLinus Torvalds
493bf2d28aSVeaceslav Falico /* Port Key definitions
503bf2d28aSVeaceslav Falico * key is determined according to the link speed, duplex and
513bf2d28aSVeaceslav Falico * user key (which is yet not supported)
523bf2d28aSVeaceslav Falico * --------------------------------------------------------------
53d22a5fc0SMahesh Bandewar * Port key | User key (10 bits) | Speed (5 bits) | Duplex|
543bf2d28aSVeaceslav Falico * --------------------------------------------------------------
55d22a5fc0SMahesh Bandewar * |15 6|5 1|0
563bf2d28aSVeaceslav Falico */
57cb8dda90SJianhua Xie #define AD_DUPLEX_KEY_MASKS 0x1
58cb8dda90SJianhua Xie #define AD_SPEED_KEY_MASKS 0x3E
59cb8dda90SJianhua Xie #define AD_USER_KEY_MASKS 0xFFC0
601da177e4SLinus Torvalds
61cb8dda90SJianhua Xie enum ad_link_speed_type {
62cb8dda90SJianhua Xie AD_LINK_SPEED_1MBPS = 1,
63cb8dda90SJianhua Xie AD_LINK_SPEED_10MBPS,
64cb8dda90SJianhua Xie AD_LINK_SPEED_100MBPS,
65cb8dda90SJianhua Xie AD_LINK_SPEED_1000MBPS,
66424c3232SJianhua Xie AD_LINK_SPEED_2500MBPS,
67c7c55067SThibaut Collet AD_LINK_SPEED_5000MBPS,
68424c3232SJianhua Xie AD_LINK_SPEED_10000MBPS,
693fcd64cfSNicolas Dichtel AD_LINK_SPEED_14000MBPS,
70424c3232SJianhua Xie AD_LINK_SPEED_20000MBPS,
7119ddde1eSJarod Wilson AD_LINK_SPEED_25000MBPS,
72424c3232SJianhua Xie AD_LINK_SPEED_40000MBPS,
73c7c55067SThibaut Collet AD_LINK_SPEED_50000MBPS,
743952af4dSJiri Pirko AD_LINK_SPEED_56000MBPS,
753952af4dSJiri Pirko AD_LINK_SPEED_100000MBPS,
76ab73447cSNikolay Aleksandrov AD_LINK_SPEED_200000MBPS,
77138e3b3cSNikolay Aleksandrov AD_LINK_SPEED_400000MBPS,
7841305d37SAmit Cohen AD_LINK_SPEED_800000MBPS,
79cb8dda90SJianhua Xie };
801da177e4SLinus Torvalds
81815117adSdingtianhong /* compare MAC addresses */
82815117adSdingtianhong #define MAC_ADDRESS_EQUAL(A, B) \
83815117adSdingtianhong ether_addr_equal_64bits((const u8 *)A, (const u8 *)B)
841da177e4SLinus Torvalds
85f87fda00SEric Dumazet static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = {
86f87fda00SEric Dumazet 0, 0, 0, 0, 0, 0
87f87fda00SEric Dumazet };
88f2e44dffSJonathan Toppins
89f2e44dffSJonathan Toppins static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL;
901da177e4SLinus Torvalds static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
911da177e4SLinus Torvalds
921d9a143eSBenjamin Poirier const u8 lacpdu_mcast_addr[ETH_ALEN + 2] __long_aligned = {
931d9a143eSBenjamin Poirier 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02
941d9a143eSBenjamin Poirier };
95e4ac4320SHolger Eitzenberger
963bf2d28aSVeaceslav Falico /* ================= main 802.3ad protocol functions ================== */
971da177e4SLinus Torvalds static int ad_lacpdu_send(struct port *port);
981c3f0b8eSMathieu Desnoyers static int ad_marker_send(struct port *port, struct bond_marker *marker);
99ee637714SMahesh Bandewar static void ad_mux_machine(struct port *port, bool *update_slave_arr);
1001da177e4SLinus Torvalds static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
1011da177e4SLinus Torvalds static void ad_tx_machine(struct port *port);
102bbef56d8SColin Ian King static void ad_periodic_machine(struct port *port, struct bond_params *bond_params);
103ee637714SMahesh Bandewar static void ad_port_selection_logic(struct port *port, bool *update_slave_arr);
104ee637714SMahesh Bandewar static void ad_agg_selection_logic(struct aggregator *aggregator,
105ee637714SMahesh Bandewar bool *update_slave_arr);
1061da177e4SLinus Torvalds static void ad_clear_agg(struct aggregator *aggregator);
1071da177e4SLinus Torvalds static void ad_initialize_agg(struct aggregator *aggregator);
1081da177e4SLinus Torvalds static void ad_initialize_port(struct port *port, int lacp_fast);
109ee637714SMahesh Bandewar static void ad_enable_collecting_distributing(struct port *port,
110ee637714SMahesh Bandewar bool *update_slave_arr);
111ee637714SMahesh Bandewar static void ad_disable_collecting_distributing(struct port *port,
112ee637714SMahesh Bandewar bool *update_slave_arr);
1133bf2d28aSVeaceslav Falico static void ad_marker_info_received(struct bond_marker *marker_info,
1143bf2d28aSVeaceslav Falico struct port *port);
1153bf2d28aSVeaceslav Falico static void ad_marker_response_received(struct bond_marker *marker,
1163bf2d28aSVeaceslav Falico struct port *port);
1177bb11dc9SMahesh Bandewar static void ad_update_actor_keys(struct port *port, bool reset);
1181da177e4SLinus Torvalds
1191da177e4SLinus Torvalds
1203bf2d28aSVeaceslav Falico /* ================= api to bonding and kernel code ================== */
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds /**
1231da177e4SLinus Torvalds * __get_bond_by_port - get the port's bonding struct
1241da177e4SLinus Torvalds * @port: the port we're looking at
1251da177e4SLinus Torvalds *
1261da177e4SLinus Torvalds * Return @port's bonding struct, or %NULL if it can't be found.
1271da177e4SLinus Torvalds */
__get_bond_by_port(struct port * port)1281da177e4SLinus Torvalds static inline struct bonding *__get_bond_by_port(struct port *port)
1291da177e4SLinus Torvalds {
1307bfc4753SBandan Das if (port->slave == NULL)
1311da177e4SLinus Torvalds return NULL;
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds return bond_get_bond_by_slave(port->slave);
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds /**
1371da177e4SLinus Torvalds * __get_first_agg - get the first aggregator in the bond
138a35e5478SLee Jones * @port: the port we're looking at
1391da177e4SLinus Torvalds *
1401da177e4SLinus Torvalds * Return the aggregator of the first slave in @bond, or %NULL if it can't be
1411da177e4SLinus Torvalds * found.
142768b9549SVeaceslav Falico * The caller must hold RCU or RTNL lock.
1431da177e4SLinus Torvalds */
__get_first_agg(struct port * port)1441da177e4SLinus Torvalds static inline struct aggregator *__get_first_agg(struct port *port)
1451da177e4SLinus Torvalds {
1461da177e4SLinus Torvalds struct bonding *bond = __get_bond_by_port(port);
147dec1e90eSnikolay@redhat.com struct slave *first_slave;
148768b9549SVeaceslav Falico struct aggregator *agg;
1491da177e4SLinus Torvalds
150be79bd04Sdingtianhong /* If there's no bond for this port, or bond has no slaves */
151dec1e90eSnikolay@redhat.com if (bond == NULL)
1521da177e4SLinus Torvalds return NULL;
1533bf2d28aSVeaceslav Falico
154be79bd04Sdingtianhong rcu_read_lock();
155be79bd04Sdingtianhong first_slave = bond_first_slave_rcu(bond);
1563fdddd85Sdingtianhong agg = first_slave ? &(SLAVE_AD_INFO(first_slave)->aggregator) : NULL;
157be79bd04Sdingtianhong rcu_read_unlock();
1583bf2d28aSVeaceslav Falico
159768b9549SVeaceslav Falico return agg;
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds
1623bf2d28aSVeaceslav Falico /**
1633bf2d28aSVeaceslav Falico * __agg_has_partner - see if we have a partner
1643bf2d28aSVeaceslav Falico * @agg: the agregator we're looking at
165fd989c83SJay Vosburgh *
166fd989c83SJay Vosburgh * Return nonzero if aggregator has a partner (denoted by a non-zero ether
167fd989c83SJay Vosburgh * address for the partner). Return 0 if not.
168fd989c83SJay Vosburgh */
__agg_has_partner(struct aggregator * agg)169fd989c83SJay Vosburgh static inline int __agg_has_partner(struct aggregator *agg)
170fd989c83SJay Vosburgh {
171fd989c83SJay Vosburgh return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
172fd989c83SJay Vosburgh }
173fd989c83SJay Vosburgh
1741da177e4SLinus Torvalds /**
1751da177e4SLinus Torvalds * __disable_port - disable the port's slave
1761da177e4SLinus Torvalds * @port: the port we're looking at
1771da177e4SLinus Torvalds */
__disable_port(struct port * port)1781da177e4SLinus Torvalds static inline void __disable_port(struct port *port)
1791da177e4SLinus Torvalds {
1805e5b0665Sdingtianhong bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds /**
1841da177e4SLinus Torvalds * __enable_port - enable the port's slave, if it's up
1851da177e4SLinus Torvalds * @port: the port we're looking at
1861da177e4SLinus Torvalds */
__enable_port(struct port * port)1871da177e4SLinus Torvalds static inline void __enable_port(struct port *port)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds struct slave *slave = port->slave;
1901da177e4SLinus Torvalds
191b6adc610SVeaceslav Falico if ((slave->link == BOND_LINK_UP) && bond_slave_is_up(slave))
1925e5b0665Sdingtianhong bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds /**
1961da177e4SLinus Torvalds * __port_is_enabled - check if the port's slave is in active state
1971da177e4SLinus Torvalds * @port: the port we're looking at
1981da177e4SLinus Torvalds */
__port_is_enabled(struct port * port)1991da177e4SLinus Torvalds static inline int __port_is_enabled(struct port *port)
2001da177e4SLinus Torvalds {
201e30bc066SJiri Pirko return bond_is_active_slave(port->slave);
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds /**
2051da177e4SLinus Torvalds * __get_agg_selection_mode - get the aggregator selection mode
2061da177e4SLinus Torvalds * @port: the port we're looking at
2071da177e4SLinus Torvalds *
208fd989c83SJay Vosburgh * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT.
2091da177e4SLinus Torvalds */
__get_agg_selection_mode(struct port * port)2101da177e4SLinus Torvalds static inline u32 __get_agg_selection_mode(struct port *port)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds struct bonding *bond = __get_bond_by_port(port);
2131da177e4SLinus Torvalds
2147bfc4753SBandan Das if (bond == NULL)
215fd989c83SJay Vosburgh return BOND_AD_STABLE;
2161da177e4SLinus Torvalds
2171a14fbcbSPeter Pan(潘卫平) return bond->params.ad_select;
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds /**
2211da177e4SLinus Torvalds * __check_agg_selection_timer - check if the selection timer has expired
2221da177e4SLinus Torvalds * @port: the port we're looking at
2231da177e4SLinus Torvalds */
__check_agg_selection_timer(struct port * port)2241da177e4SLinus Torvalds static inline int __check_agg_selection_timer(struct port *port)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds struct bonding *bond = __get_bond_by_port(port);
2271da177e4SLinus Torvalds
2287bfc4753SBandan Das if (bond == NULL)
2291da177e4SLinus Torvalds return 0;
2301da177e4SLinus Torvalds
2319ceaf6f7SEric Dumazet return atomic_read(&BOND_AD_INFO(bond).agg_select_timer) ? 1 : 0;
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds /**
2351da177e4SLinus Torvalds * __get_link_speed - get a port's speed
2361da177e4SLinus Torvalds * @port: the port we're looking at
2371da177e4SLinus Torvalds *
238cb8dda90SJianhua Xie * Return @port's speed in 802.3ad enum format. i.e. one of:
2391da177e4SLinus Torvalds * 0,
240cb8dda90SJianhua Xie * %AD_LINK_SPEED_10MBPS,
241cb8dda90SJianhua Xie * %AD_LINK_SPEED_100MBPS,
242cb8dda90SJianhua Xie * %AD_LINK_SPEED_1000MBPS,
243424c3232SJianhua Xie * %AD_LINK_SPEED_2500MBPS,
244c7c55067SThibaut Collet * %AD_LINK_SPEED_5000MBPS,
245cb8dda90SJianhua Xie * %AD_LINK_SPEED_10000MBPS
2463fcd64cfSNicolas Dichtel * %AD_LINK_SPEED_14000MBPS,
247424c3232SJianhua Xie * %AD_LINK_SPEED_20000MBPS
24819ddde1eSJarod Wilson * %AD_LINK_SPEED_25000MBPS
249424c3232SJianhua Xie * %AD_LINK_SPEED_40000MBPS
250c7c55067SThibaut Collet * %AD_LINK_SPEED_50000MBPS
251424c3232SJianhua Xie * %AD_LINK_SPEED_56000MBPS
2523952af4dSJiri Pirko * %AD_LINK_SPEED_100000MBPS
253ab73447cSNikolay Aleksandrov * %AD_LINK_SPEED_200000MBPS
254138e3b3cSNikolay Aleksandrov * %AD_LINK_SPEED_400000MBPS
25541305d37SAmit Cohen * %AD_LINK_SPEED_800000MBPS
2561da177e4SLinus Torvalds */
__get_link_speed(struct port * port)2571da177e4SLinus Torvalds static u16 __get_link_speed(struct port *port)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds struct slave *slave = port->slave;
2601da177e4SLinus Torvalds u16 speed;
2611da177e4SLinus Torvalds
2623bf2d28aSVeaceslav Falico /* this if covers only a special case: when the configuration starts
2633bf2d28aSVeaceslav Falico * with link down, it sets the speed to 0.
2643bf2d28aSVeaceslav Falico * This is done in spite of the fact that the e100 driver reports 0
2653bf2d28aSVeaceslav Falico * to be compatible with MVT in the future.
2663bf2d28aSVeaceslav Falico */
2677bfc4753SBandan Das if (slave->link != BOND_LINK_UP)
2681da177e4SLinus Torvalds speed = 0;
2697bfc4753SBandan Das else {
2701da177e4SLinus Torvalds switch (slave->speed) {
2711da177e4SLinus Torvalds case SPEED_10:
272cb8dda90SJianhua Xie speed = AD_LINK_SPEED_10MBPS;
2731da177e4SLinus Torvalds break;
2741da177e4SLinus Torvalds
2751da177e4SLinus Torvalds case SPEED_100:
276cb8dda90SJianhua Xie speed = AD_LINK_SPEED_100MBPS;
2771da177e4SLinus Torvalds break;
2781da177e4SLinus Torvalds
2791da177e4SLinus Torvalds case SPEED_1000:
280cb8dda90SJianhua Xie speed = AD_LINK_SPEED_1000MBPS;
2811da177e4SLinus Torvalds break;
2821da177e4SLinus Torvalds
283424c3232SJianhua Xie case SPEED_2500:
284424c3232SJianhua Xie speed = AD_LINK_SPEED_2500MBPS;
285424c3232SJianhua Xie break;
286424c3232SJianhua Xie
287c7c55067SThibaut Collet case SPEED_5000:
288c7c55067SThibaut Collet speed = AD_LINK_SPEED_5000MBPS;
289c7c55067SThibaut Collet break;
290c7c55067SThibaut Collet
29194dbffd5SJay Vosburgh case SPEED_10000:
292cb8dda90SJianhua Xie speed = AD_LINK_SPEED_10000MBPS;
29394dbffd5SJay Vosburgh break;
29494dbffd5SJay Vosburgh
2953fcd64cfSNicolas Dichtel case SPEED_14000:
2963fcd64cfSNicolas Dichtel speed = AD_LINK_SPEED_14000MBPS;
2973fcd64cfSNicolas Dichtel break;
2983fcd64cfSNicolas Dichtel
299424c3232SJianhua Xie case SPEED_20000:
300424c3232SJianhua Xie speed = AD_LINK_SPEED_20000MBPS;
301424c3232SJianhua Xie break;
302424c3232SJianhua Xie
30319ddde1eSJarod Wilson case SPEED_25000:
30419ddde1eSJarod Wilson speed = AD_LINK_SPEED_25000MBPS;
30519ddde1eSJarod Wilson break;
30619ddde1eSJarod Wilson
307424c3232SJianhua Xie case SPEED_40000:
308424c3232SJianhua Xie speed = AD_LINK_SPEED_40000MBPS;
309424c3232SJianhua Xie break;
310424c3232SJianhua Xie
311c7c55067SThibaut Collet case SPEED_50000:
312c7c55067SThibaut Collet speed = AD_LINK_SPEED_50000MBPS;
313c7c55067SThibaut Collet break;
314c7c55067SThibaut Collet
315424c3232SJianhua Xie case SPEED_56000:
316424c3232SJianhua Xie speed = AD_LINK_SPEED_56000MBPS;
317424c3232SJianhua Xie break;
318424c3232SJianhua Xie
3193952af4dSJiri Pirko case SPEED_100000:
3203952af4dSJiri Pirko speed = AD_LINK_SPEED_100000MBPS;
3213952af4dSJiri Pirko break;
3223952af4dSJiri Pirko
323ab73447cSNikolay Aleksandrov case SPEED_200000:
324ab73447cSNikolay Aleksandrov speed = AD_LINK_SPEED_200000MBPS;
325ab73447cSNikolay Aleksandrov break;
326ab73447cSNikolay Aleksandrov
327138e3b3cSNikolay Aleksandrov case SPEED_400000:
328138e3b3cSNikolay Aleksandrov speed = AD_LINK_SPEED_400000MBPS;
329138e3b3cSNikolay Aleksandrov break;
330138e3b3cSNikolay Aleksandrov
33141305d37SAmit Cohen case SPEED_800000:
33241305d37SAmit Cohen speed = AD_LINK_SPEED_800000MBPS;
33341305d37SAmit Cohen break;
33441305d37SAmit Cohen
3351da177e4SLinus Torvalds default:
3363bf2d28aSVeaceslav Falico /* unknown speed value from ethtool. shouldn't happen */
337cd99c377SNicolas Dichtel if (slave->speed != SPEED_UNKNOWN)
3385edf55adSIdo Schimmel pr_err_once("%s: (slave %s): unknown ethtool speed (%d) for port %d (set it to 0)\n",
339cd99c377SNicolas Dichtel slave->bond->dev->name,
34017720981SJarod Wilson slave->dev->name, slave->speed,
341cd99c377SNicolas Dichtel port->actor_port_number);
3423bf2d28aSVeaceslav Falico speed = 0;
3431da177e4SLinus Torvalds break;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds
34717720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Port %d Received link speed %d update from adapter\n",
348a4aee5c8SJoe Perches port->actor_port_number, speed);
3491da177e4SLinus Torvalds return speed;
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds /**
3531da177e4SLinus Torvalds * __get_duplex - get a port's duplex
3541da177e4SLinus Torvalds * @port: the port we're looking at
3551da177e4SLinus Torvalds *
3561da177e4SLinus Torvalds * Return @port's duplex in 802.3ad bitmask format. i.e.:
3571da177e4SLinus Torvalds * 0x01 if in full duplex
3581da177e4SLinus Torvalds * 0x00 otherwise
3591da177e4SLinus Torvalds */
__get_duplex(struct port * port)3601da177e4SLinus Torvalds static u8 __get_duplex(struct port *port)
3611da177e4SLinus Torvalds {
3621da177e4SLinus Torvalds struct slave *slave = port->slave;
363b25c2e7dSMahesh Bandewar u8 retval = 0x0;
3641da177e4SLinus Torvalds
3653bf2d28aSVeaceslav Falico /* handling a special case: when the configuration starts with
3663bf2d28aSVeaceslav Falico * link down, it sets the duplex to 0.
3673bf2d28aSVeaceslav Falico */
368b25c2e7dSMahesh Bandewar if (slave->link == BOND_LINK_UP) {
3691da177e4SLinus Torvalds switch (slave->duplex) {
3701da177e4SLinus Torvalds case DUPLEX_FULL:
3711da177e4SLinus Torvalds retval = 0x1;
37217720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Port %d Received status full duplex update from adapter\n",
373a4aee5c8SJoe Perches port->actor_port_number);
3741da177e4SLinus Torvalds break;
3751da177e4SLinus Torvalds case DUPLEX_HALF:
3761da177e4SLinus Torvalds default:
3771da177e4SLinus Torvalds retval = 0x0;
37817720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Port %d Received status NOT full duplex update from adapter\n",
379a4aee5c8SJoe Perches port->actor_port_number);
3801da177e4SLinus Torvalds break;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds }
3831da177e4SLinus Torvalds return retval;
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds
__ad_actor_update_port(struct port * port)3865ee14e6dSNikolay Aleksandrov static void __ad_actor_update_port(struct port *port)
3875ee14e6dSNikolay Aleksandrov {
3885ee14e6dSNikolay Aleksandrov const struct bonding *bond = bond_get_bond_by_slave(port->slave);
3895ee14e6dSNikolay Aleksandrov
3905ee14e6dSNikolay Aleksandrov port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
3915ee14e6dSNikolay Aleksandrov port->actor_system_priority = BOND_AD_INFO(bond).system.sys_priority;
3925ee14e6dSNikolay Aleksandrov }
3935ee14e6dSNikolay Aleksandrov
3943bf2d28aSVeaceslav Falico /* Conversions */
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds /**
3971da177e4SLinus Torvalds * __ad_timer_to_ticks - convert a given timer type to AD module ticks
3981da177e4SLinus Torvalds * @timer_type: which timer to operate
3991da177e4SLinus Torvalds * @par: timer parameter. see below
4001da177e4SLinus Torvalds *
4011da177e4SLinus Torvalds * If @timer_type is %current_while_timer, @par indicates long/short timer.
4021da177e4SLinus Torvalds * If @timer_type is %periodic_timer, @par is one of %FAST_PERIODIC_TIME,
4031da177e4SLinus Torvalds * %SLOW_PERIODIC_TIME.
4041da177e4SLinus Torvalds */
__ad_timer_to_ticks(u16 timer_type,u16 par)4051da177e4SLinus Torvalds static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
4061da177e4SLinus Torvalds {
407128ea6c3SBandan Das u16 retval = 0; /* to silence the compiler */
4081da177e4SLinus Torvalds
4091da177e4SLinus Torvalds switch (timer_type) {
4103bf2d28aSVeaceslav Falico case AD_CURRENT_WHILE_TIMER: /* for rx machine usage */
4117bfc4753SBandan Das if (par)
4123bf2d28aSVeaceslav Falico retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec);
4137bfc4753SBandan Das else
4143bf2d28aSVeaceslav Falico retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec);
4151da177e4SLinus Torvalds break;
4163bf2d28aSVeaceslav Falico case AD_ACTOR_CHURN_TIMER: /* for local churn machine */
4171da177e4SLinus Torvalds retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
4181da177e4SLinus Torvalds break;
4193bf2d28aSVeaceslav Falico case AD_PERIODIC_TIMER: /* for periodic machine */
4203bf2d28aSVeaceslav Falico retval = (par*ad_ticks_per_sec); /* long timeout */
4211da177e4SLinus Torvalds break;
4223bf2d28aSVeaceslav Falico case AD_PARTNER_CHURN_TIMER: /* for remote churn machine */
4231da177e4SLinus Torvalds retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
4241da177e4SLinus Torvalds break;
4253bf2d28aSVeaceslav Falico case AD_WAIT_WHILE_TIMER: /* for selection machine */
4261da177e4SLinus Torvalds retval = (AD_AGGREGATE_WAIT_TIME*ad_ticks_per_sec);
4271da177e4SLinus Torvalds break;
4281da177e4SLinus Torvalds }
4293bf2d28aSVeaceslav Falico
4301da177e4SLinus Torvalds return retval;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds
4331da177e4SLinus Torvalds
4343bf2d28aSVeaceslav Falico /* ================= ad_rx_machine helper functions ================== */
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds /**
4372d6682dbSJay Vosburgh * __choose_matched - update a port's matched variable from a received lacpdu
4382d6682dbSJay Vosburgh * @lacpdu: the lacpdu we've received
4392d6682dbSJay Vosburgh * @port: the port we're looking at
4402d6682dbSJay Vosburgh *
4412d6682dbSJay Vosburgh * Update the value of the matched variable, using parameter values from a
4422d6682dbSJay Vosburgh * newly received lacpdu. Parameter values for the partner carried in the
4432d6682dbSJay Vosburgh * received PDU are compared with the corresponding operational parameter
4442d6682dbSJay Vosburgh * values for the actor. Matched is set to TRUE if all of these parameters
4452d6682dbSJay Vosburgh * match and the PDU parameter partner_state.aggregation has the same value as
4462d6682dbSJay Vosburgh * actor_oper_port_state.aggregation and lacp will actively maintain the link
4472d6682dbSJay Vosburgh * in the aggregation. Matched is also set to TRUE if the value of
4482d6682dbSJay Vosburgh * actor_state.aggregation in the received PDU is set to FALSE, i.e., indicates
4492d6682dbSJay Vosburgh * an individual link and lacp will actively maintain the link. Otherwise,
4502d6682dbSJay Vosburgh * matched is set to FALSE. LACP is considered to be actively maintaining the
4512d6682dbSJay Vosburgh * link if either the PDU's actor_state.lacp_activity variable is TRUE or both
4522d6682dbSJay Vosburgh * the actor's actor_oper_port_state.lacp_activity and the PDU's
4532d6682dbSJay Vosburgh * partner_state.lacp_activity variables are TRUE.
4542d6682dbSJay Vosburgh *
4552d6682dbSJay Vosburgh * Note: the AD_PORT_MATCHED "variable" is not specified by 802.3ad; it is
4562d6682dbSJay Vosburgh * used here to implement the language from 802.3ad 43.4.9 that requires
4572d6682dbSJay Vosburgh * recordPDU to "match" the LACPDU parameters to the stored values.
4582d6682dbSJay Vosburgh */
__choose_matched(struct lacpdu * lacpdu,struct port * port)4592d6682dbSJay Vosburgh static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
4602d6682dbSJay Vosburgh {
461815117adSdingtianhong /* check if all parameters are alike
462815117adSdingtianhong * or this is individual link(aggregation == FALSE)
463815117adSdingtianhong * then update the state machine Matched variable.
464815117adSdingtianhong */
4652d6682dbSJay Vosburgh if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
4662d6682dbSJay Vosburgh (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
467815117adSdingtianhong MAC_ADDRESS_EQUAL(&(lacpdu->partner_system), &(port->actor_system)) &&
4682d6682dbSJay Vosburgh (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
4692d6682dbSJay Vosburgh (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
470c1e46990SAndy Roulin ((lacpdu->partner_state & LACP_STATE_AGGREGATION) == (port->actor_oper_port_state & LACP_STATE_AGGREGATION))) ||
471c1e46990SAndy Roulin ((lacpdu->actor_state & LACP_STATE_AGGREGATION) == 0)
4722d6682dbSJay Vosburgh ) {
4732d6682dbSJay Vosburgh port->sm_vars |= AD_PORT_MATCHED;
4742d6682dbSJay Vosburgh } else {
4752d6682dbSJay Vosburgh port->sm_vars &= ~AD_PORT_MATCHED;
4762d6682dbSJay Vosburgh }
4772d6682dbSJay Vosburgh }
4782d6682dbSJay Vosburgh
4792d6682dbSJay Vosburgh /**
4801da177e4SLinus Torvalds * __record_pdu - record parameters from a received lacpdu
4811da177e4SLinus Torvalds * @lacpdu: the lacpdu we've received
4821da177e4SLinus Torvalds * @port: the port we're looking at
4831da177e4SLinus Torvalds *
4841da177e4SLinus Torvalds * Record the parameter values for the Actor carried in a received lacpdu as
4851da177e4SLinus Torvalds * the current partner operational parameter values and sets
4861da177e4SLinus Torvalds * actor_oper_port_state.defaulted to FALSE.
4871da177e4SLinus Torvalds */
__record_pdu(struct lacpdu * lacpdu,struct port * port)4881da177e4SLinus Torvalds static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
4891da177e4SLinus Torvalds {
4901da177e4SLinus Torvalds if (lacpdu && port) {
491b99d6ba9SHolger Eitzenberger struct port_params *partner = &port->partner_oper;
492b99d6ba9SHolger Eitzenberger
4932d6682dbSJay Vosburgh __choose_matched(lacpdu, port);
4943bf2d28aSVeaceslav Falico /* record the new parameter values for the partner
4953bf2d28aSVeaceslav Falico * operational
4963bf2d28aSVeaceslav Falico */
497b99d6ba9SHolger Eitzenberger partner->port_number = ntohs(lacpdu->actor_port);
498b99d6ba9SHolger Eitzenberger partner->port_priority = ntohs(lacpdu->actor_port_priority);
499b99d6ba9SHolger Eitzenberger partner->system = lacpdu->actor_system;
500b99d6ba9SHolger Eitzenberger partner->system_priority = ntohs(lacpdu->actor_system_priority);
501b99d6ba9SHolger Eitzenberger partner->key = ntohs(lacpdu->actor_key);
502b99d6ba9SHolger Eitzenberger partner->port_state = lacpdu->actor_state;
5031da177e4SLinus Torvalds
5043bf2d28aSVeaceslav Falico /* set actor_oper_port_state.defaulted to FALSE */
505c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_DEFAULTED;
5061da177e4SLinus Torvalds
5073bf2d28aSVeaceslav Falico /* set the partner sync. to on if the partner is sync,
5083bf2d28aSVeaceslav Falico * and the port is matched
5093bf2d28aSVeaceslav Falico */
51063b46242SWilson Kok if ((port->sm_vars & AD_PORT_MATCHED) &&
511c1e46990SAndy Roulin (lacpdu->actor_state & LACP_STATE_SYNCHRONIZATION)) {
512c1e46990SAndy Roulin partner->port_state |= LACP_STATE_SYNCHRONIZATION;
51317720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
51417720981SJarod Wilson "partner sync=1\n");
51563b46242SWilson Kok } else {
516c1e46990SAndy Roulin partner->port_state &= ~LACP_STATE_SYNCHRONIZATION;
51717720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
51817720981SJarod Wilson "partner sync=0\n");
51963b46242SWilson Kok }
5201da177e4SLinus Torvalds }
5211da177e4SLinus Torvalds }
5221da177e4SLinus Torvalds
5231da177e4SLinus Torvalds /**
5241da177e4SLinus Torvalds * __record_default - record default parameters
5251da177e4SLinus Torvalds * @port: the port we're looking at
5261da177e4SLinus Torvalds *
5271da177e4SLinus Torvalds * This function records the default parameter values for the partner carried
5281da177e4SLinus Torvalds * in the Partner Admin parameters as the current partner operational parameter
5291da177e4SLinus Torvalds * values and sets actor_oper_port_state.defaulted to TRUE.
5301da177e4SLinus Torvalds */
__record_default(struct port * port)5311da177e4SLinus Torvalds static void __record_default(struct port *port)
5321da177e4SLinus Torvalds {
5331da177e4SLinus Torvalds if (port) {
5343bf2d28aSVeaceslav Falico /* record the partner admin parameters */
5355eefd1adSHolger Eitzenberger memcpy(&port->partner_oper, &port->partner_admin,
5365eefd1adSHolger Eitzenberger sizeof(struct port_params));
5371da177e4SLinus Torvalds
5383bf2d28aSVeaceslav Falico /* set actor_oper_port_state.defaulted to true */
539c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_DEFAULTED;
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds /**
5441da177e4SLinus Torvalds * __update_selected - update a port's Selected variable from a received lacpdu
5451da177e4SLinus Torvalds * @lacpdu: the lacpdu we've received
5461da177e4SLinus Torvalds * @port: the port we're looking at
5471da177e4SLinus Torvalds *
5481da177e4SLinus Torvalds * Update the value of the selected variable, using parameter values from a
5491da177e4SLinus Torvalds * newly received lacpdu. The parameter values for the Actor carried in the
5501da177e4SLinus Torvalds * received PDU are compared with the corresponding operational parameter
5511da177e4SLinus Torvalds * values for the ports partner. If one or more of the comparisons shows that
5521da177e4SLinus Torvalds * the value(s) received in the PDU differ from the current operational values,
5531da177e4SLinus Torvalds * then selected is set to FALSE and actor_oper_port_state.synchronization is
5541da177e4SLinus Torvalds * set to out_of_sync. Otherwise, selected remains unchanged.
5551da177e4SLinus Torvalds */
__update_selected(struct lacpdu * lacpdu,struct port * port)5561da177e4SLinus Torvalds static void __update_selected(struct lacpdu *lacpdu, struct port *port)
5571da177e4SLinus Torvalds {
5581da177e4SLinus Torvalds if (lacpdu && port) {
559ce6a49adSHolger Eitzenberger const struct port_params *partner = &port->partner_oper;
560ce6a49adSHolger Eitzenberger
561815117adSdingtianhong /* check if any parameter is different then
562815117adSdingtianhong * update the state machine selected variable.
563815117adSdingtianhong */
5648e95a202SJoe Perches if (ntohs(lacpdu->actor_port) != partner->port_number ||
5658e95a202SJoe Perches ntohs(lacpdu->actor_port_priority) != partner->port_priority ||
566815117adSdingtianhong !MAC_ADDRESS_EQUAL(&lacpdu->actor_system, &partner->system) ||
5678e95a202SJoe Perches ntohs(lacpdu->actor_system_priority) != partner->system_priority ||
5688e95a202SJoe Perches ntohs(lacpdu->actor_key) != partner->key ||
569c1e46990SAndy Roulin (lacpdu->actor_state & LACP_STATE_AGGREGATION) != (partner->port_state & LACP_STATE_AGGREGATION)) {
5701da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_SELECTED;
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds /**
5761da177e4SLinus Torvalds * __update_default_selected - update a port's Selected variable from Partner
5771da177e4SLinus Torvalds * @port: the port we're looking at
5781da177e4SLinus Torvalds *
5791da177e4SLinus Torvalds * This function updates the value of the selected variable, using the partner
5801da177e4SLinus Torvalds * administrative parameter values. The administrative values are compared with
5811da177e4SLinus Torvalds * the corresponding operational parameter values for the partner. If one or
5821da177e4SLinus Torvalds * more of the comparisons shows that the administrative value(s) differ from
5831da177e4SLinus Torvalds * the current operational values, then Selected is set to FALSE and
5841da177e4SLinus Torvalds * actor_oper_port_state.synchronization is set to OUT_OF_SYNC. Otherwise,
5851da177e4SLinus Torvalds * Selected remains unchanged.
5861da177e4SLinus Torvalds */
__update_default_selected(struct port * port)5871da177e4SLinus Torvalds static void __update_default_selected(struct port *port)
5881da177e4SLinus Torvalds {
5891da177e4SLinus Torvalds if (port) {
5903c52065fSHolger Eitzenberger const struct port_params *admin = &port->partner_admin;
5913c52065fSHolger Eitzenberger const struct port_params *oper = &port->partner_oper;
5923c52065fSHolger Eitzenberger
593815117adSdingtianhong /* check if any parameter is different then
594815117adSdingtianhong * update the state machine selected variable.
595815117adSdingtianhong */
5968e95a202SJoe Perches if (admin->port_number != oper->port_number ||
5978e95a202SJoe Perches admin->port_priority != oper->port_priority ||
598815117adSdingtianhong !MAC_ADDRESS_EQUAL(&admin->system, &oper->system) ||
5998e95a202SJoe Perches admin->system_priority != oper->system_priority ||
6008e95a202SJoe Perches admin->key != oper->key ||
601c1e46990SAndy Roulin (admin->port_state & LACP_STATE_AGGREGATION)
602c1e46990SAndy Roulin != (oper->port_state & LACP_STATE_AGGREGATION)) {
6031da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_SELECTED;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds }
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds
6081da177e4SLinus Torvalds /**
6091da177e4SLinus Torvalds * __update_ntt - update a port's ntt variable from a received lacpdu
6101da177e4SLinus Torvalds * @lacpdu: the lacpdu we've received
6111da177e4SLinus Torvalds * @port: the port we're looking at
6121da177e4SLinus Torvalds *
6131da177e4SLinus Torvalds * Updates the value of the ntt variable, using parameter values from a newly
6141da177e4SLinus Torvalds * received lacpdu. The parameter values for the partner carried in the
6151da177e4SLinus Torvalds * received PDU are compared with the corresponding operational parameter
6161da177e4SLinus Torvalds * values for the Actor. If one or more of the comparisons shows that the
6171da177e4SLinus Torvalds * value(s) received in the PDU differ from the current operational values,
6181da177e4SLinus Torvalds * then ntt is set to TRUE. Otherwise, ntt remains unchanged.
6191da177e4SLinus Torvalds */
__update_ntt(struct lacpdu * lacpdu,struct port * port)6201da177e4SLinus Torvalds static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
6211da177e4SLinus Torvalds {
622815117adSdingtianhong /* validate lacpdu and port */
6231da177e4SLinus Torvalds if (lacpdu && port) {
624815117adSdingtianhong /* check if any parameter is different then
625815117adSdingtianhong * update the port->ntt.
626815117adSdingtianhong */
62789cc76f9SJay Vosburgh if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
62889cc76f9SJay Vosburgh (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
629815117adSdingtianhong !MAC_ADDRESS_EQUAL(&(lacpdu->partner_system), &(port->actor_system)) ||
63089cc76f9SJay Vosburgh (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
63189cc76f9SJay Vosburgh (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
632c1e46990SAndy Roulin ((lacpdu->partner_state & LACP_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY)) ||
633c1e46990SAndy Roulin ((lacpdu->partner_state & LACP_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & LACP_STATE_LACP_TIMEOUT)) ||
634c1e46990SAndy Roulin ((lacpdu->partner_state & LACP_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) ||
635c1e46990SAndy Roulin ((lacpdu->partner_state & LACP_STATE_AGGREGATION) != (port->actor_oper_port_state & LACP_STATE_AGGREGATION))
6361da177e4SLinus Torvalds ) {
637d238d458SHolger Eitzenberger port->ntt = true;
6381da177e4SLinus Torvalds }
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds
6421da177e4SLinus Torvalds /**
6431da177e4SLinus Torvalds * __agg_ports_are_ready - check if all ports in an aggregator are ready
6441da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
6451da177e4SLinus Torvalds *
6461da177e4SLinus Torvalds */
__agg_ports_are_ready(struct aggregator * aggregator)6471da177e4SLinus Torvalds static int __agg_ports_are_ready(struct aggregator *aggregator)
6481da177e4SLinus Torvalds {
6491da177e4SLinus Torvalds struct port *port;
6501da177e4SLinus Torvalds int retval = 1;
6511da177e4SLinus Torvalds
6521da177e4SLinus Torvalds if (aggregator) {
6533bf2d28aSVeaceslav Falico /* scan all ports in this aggregator to verfy if they are
6543bf2d28aSVeaceslav Falico * all ready.
6553bf2d28aSVeaceslav Falico */
656128ea6c3SBandan Das for (port = aggregator->lag_ports;
657128ea6c3SBandan Das port;
658128ea6c3SBandan Das port = port->next_port_in_aggregator) {
6591da177e4SLinus Torvalds if (!(port->sm_vars & AD_PORT_READY_N)) {
6601da177e4SLinus Torvalds retval = 0;
6611da177e4SLinus Torvalds break;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds }
6641da177e4SLinus Torvalds }
6651da177e4SLinus Torvalds
6661da177e4SLinus Torvalds return retval;
6671da177e4SLinus Torvalds }
6681da177e4SLinus Torvalds
6691da177e4SLinus Torvalds /**
6701da177e4SLinus Torvalds * __set_agg_ports_ready - set value of Ready bit in all ports of an aggregator
6711da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
6721da177e4SLinus Torvalds * @val: Should the ports' ready bit be set on or off
6731da177e4SLinus Torvalds *
6741da177e4SLinus Torvalds */
__set_agg_ports_ready(struct aggregator * aggregator,int val)6751da177e4SLinus Torvalds static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
6761da177e4SLinus Torvalds {
6771da177e4SLinus Torvalds struct port *port;
6781da177e4SLinus Torvalds
679128ea6c3SBandan Das for (port = aggregator->lag_ports; port;
680128ea6c3SBandan Das port = port->next_port_in_aggregator) {
6817bfc4753SBandan Das if (val)
6821da177e4SLinus Torvalds port->sm_vars |= AD_PORT_READY;
6837bfc4753SBandan Das else
6841da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_READY;
6851da177e4SLinus Torvalds }
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds
__agg_active_ports(struct aggregator * agg)6880622cab0SJay Vosburgh static int __agg_active_ports(struct aggregator *agg)
6890622cab0SJay Vosburgh {
6900622cab0SJay Vosburgh struct port *port;
6910622cab0SJay Vosburgh int active = 0;
6920622cab0SJay Vosburgh
6930622cab0SJay Vosburgh for (port = agg->lag_ports; port;
6940622cab0SJay Vosburgh port = port->next_port_in_aggregator) {
6950622cab0SJay Vosburgh if (port->is_enabled)
6960622cab0SJay Vosburgh active++;
6970622cab0SJay Vosburgh }
6980622cab0SJay Vosburgh
6990622cab0SJay Vosburgh return active;
7000622cab0SJay Vosburgh }
7010622cab0SJay Vosburgh
7021da177e4SLinus Torvalds /**
7031da177e4SLinus Torvalds * __get_agg_bandwidth - get the total bandwidth of an aggregator
7041da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
7051da177e4SLinus Torvalds *
7061da177e4SLinus Torvalds */
__get_agg_bandwidth(struct aggregator * aggregator)7071da177e4SLinus Torvalds static u32 __get_agg_bandwidth(struct aggregator *aggregator)
7081da177e4SLinus Torvalds {
7090622cab0SJay Vosburgh int nports = __agg_active_ports(aggregator);
7101da177e4SLinus Torvalds u32 bandwidth = 0;
7111da177e4SLinus Torvalds
7120622cab0SJay Vosburgh if (nports) {
71365cce19cSDavid Decotigny switch (__get_link_speed(aggregator->lag_ports)) {
714cb8dda90SJianhua Xie case AD_LINK_SPEED_1MBPS:
7150622cab0SJay Vosburgh bandwidth = nports;
7161da177e4SLinus Torvalds break;
717cb8dda90SJianhua Xie case AD_LINK_SPEED_10MBPS:
7180622cab0SJay Vosburgh bandwidth = nports * 10;
7191da177e4SLinus Torvalds break;
720cb8dda90SJianhua Xie case AD_LINK_SPEED_100MBPS:
7210622cab0SJay Vosburgh bandwidth = nports * 100;
7221da177e4SLinus Torvalds break;
723cb8dda90SJianhua Xie case AD_LINK_SPEED_1000MBPS:
7240622cab0SJay Vosburgh bandwidth = nports * 1000;
7251da177e4SLinus Torvalds break;
726424c3232SJianhua Xie case AD_LINK_SPEED_2500MBPS:
7270622cab0SJay Vosburgh bandwidth = nports * 2500;
728424c3232SJianhua Xie break;
729c7c55067SThibaut Collet case AD_LINK_SPEED_5000MBPS:
730c7c55067SThibaut Collet bandwidth = nports * 5000;
731c7c55067SThibaut Collet break;
732cb8dda90SJianhua Xie case AD_LINK_SPEED_10000MBPS:
7330622cab0SJay Vosburgh bandwidth = nports * 10000;
73494dbffd5SJay Vosburgh break;
7353fcd64cfSNicolas Dichtel case AD_LINK_SPEED_14000MBPS:
7363fcd64cfSNicolas Dichtel bandwidth = nports * 14000;
7373fcd64cfSNicolas Dichtel break;
738424c3232SJianhua Xie case AD_LINK_SPEED_20000MBPS:
7390622cab0SJay Vosburgh bandwidth = nports * 20000;
740424c3232SJianhua Xie break;
74119ddde1eSJarod Wilson case AD_LINK_SPEED_25000MBPS:
74219ddde1eSJarod Wilson bandwidth = nports * 25000;
74319ddde1eSJarod Wilson break;
744424c3232SJianhua Xie case AD_LINK_SPEED_40000MBPS:
7450622cab0SJay Vosburgh bandwidth = nports * 40000;
746424c3232SJianhua Xie break;
747c7c55067SThibaut Collet case AD_LINK_SPEED_50000MBPS:
748c7c55067SThibaut Collet bandwidth = nports * 50000;
749c7c55067SThibaut Collet break;
750424c3232SJianhua Xie case AD_LINK_SPEED_56000MBPS:
7510622cab0SJay Vosburgh bandwidth = nports * 56000;
752424c3232SJianhua Xie break;
7533952af4dSJiri Pirko case AD_LINK_SPEED_100000MBPS:
7540622cab0SJay Vosburgh bandwidth = nports * 100000;
7553952af4dSJiri Pirko break;
756ab73447cSNikolay Aleksandrov case AD_LINK_SPEED_200000MBPS:
757ab73447cSNikolay Aleksandrov bandwidth = nports * 200000;
758ab73447cSNikolay Aleksandrov break;
759138e3b3cSNikolay Aleksandrov case AD_LINK_SPEED_400000MBPS:
760138e3b3cSNikolay Aleksandrov bandwidth = nports * 400000;
761138e3b3cSNikolay Aleksandrov break;
76241305d37SAmit Cohen case AD_LINK_SPEED_800000MBPS:
76341305d37SAmit Cohen bandwidth = nports * 800000;
76441305d37SAmit Cohen break;
7651da177e4SLinus Torvalds default:
7663bf2d28aSVeaceslav Falico bandwidth = 0; /* to silence the compiler */
7671da177e4SLinus Torvalds }
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds return bandwidth;
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds
7721da177e4SLinus Torvalds /**
7731da177e4SLinus Torvalds * __get_active_agg - get the current active aggregator
7741da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
77549b7624eSVeaceslav Falico *
77649b7624eSVeaceslav Falico * Caller must hold RCU lock.
7771da177e4SLinus Torvalds */
__get_active_agg(struct aggregator * aggregator)7781da177e4SLinus Torvalds static struct aggregator *__get_active_agg(struct aggregator *aggregator)
7791da177e4SLinus Torvalds {
78019177e7dSVeaceslav Falico struct bonding *bond = aggregator->slave->bond;
78119177e7dSVeaceslav Falico struct list_head *iter;
78219177e7dSVeaceslav Falico struct slave *slave;
7831da177e4SLinus Torvalds
784be79bd04Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter)
7853fdddd85Sdingtianhong if (SLAVE_AD_INFO(slave)->aggregator.is_active)
7863fdddd85Sdingtianhong return &(SLAVE_AD_INFO(slave)->aggregator);
7871da177e4SLinus Torvalds
78819177e7dSVeaceslav Falico return NULL;
7891da177e4SLinus Torvalds }
7901da177e4SLinus Torvalds
7911da177e4SLinus Torvalds /**
7921da177e4SLinus Torvalds * __update_lacpdu_from_port - update a port's lacpdu fields
7931da177e4SLinus Torvalds * @port: the port we're looking at
7941da177e4SLinus Torvalds */
__update_lacpdu_from_port(struct port * port)7951da177e4SLinus Torvalds static inline void __update_lacpdu_from_port(struct port *port)
7961da177e4SLinus Torvalds {
7971da177e4SLinus Torvalds struct lacpdu *lacpdu = &port->lacpdu;
7983b5b35d0SHolger Eitzenberger const struct port_params *partner = &port->partner_oper;
7991da177e4SLinus Torvalds
8003bf2d28aSVeaceslav Falico /* update current actual Actor parameters
8013bf2d28aSVeaceslav Falico * lacpdu->subtype initialized
8021da177e4SLinus Torvalds * lacpdu->version_number initialized
8031da177e4SLinus Torvalds * lacpdu->tlv_type_actor_info initialized
8041da177e4SLinus Torvalds * lacpdu->actor_information_length initialized
8051da177e4SLinus Torvalds */
8061da177e4SLinus Torvalds
807d3bb52b0SAl Viro lacpdu->actor_system_priority = htons(port->actor_system_priority);
8081da177e4SLinus Torvalds lacpdu->actor_system = port->actor_system;
809d3bb52b0SAl Viro lacpdu->actor_key = htons(port->actor_oper_port_key);
810d3bb52b0SAl Viro lacpdu->actor_port_priority = htons(port->actor_port_priority);
811d3bb52b0SAl Viro lacpdu->actor_port = htons(port->actor_port_number);
8121da177e4SLinus Torvalds lacpdu->actor_state = port->actor_oper_port_state;
81317720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
81417720981SJarod Wilson "update lacpdu: actor port state %x\n",
81517720981SJarod Wilson port->actor_oper_port_state);
8161da177e4SLinus Torvalds
8171da177e4SLinus Torvalds /* lacpdu->reserved_3_1 initialized
8181da177e4SLinus Torvalds * lacpdu->tlv_type_partner_info initialized
8191da177e4SLinus Torvalds * lacpdu->partner_information_length initialized
8201da177e4SLinus Torvalds */
8211da177e4SLinus Torvalds
8223b5b35d0SHolger Eitzenberger lacpdu->partner_system_priority = htons(partner->system_priority);
8233b5b35d0SHolger Eitzenberger lacpdu->partner_system = partner->system;
8243b5b35d0SHolger Eitzenberger lacpdu->partner_key = htons(partner->key);
8253b5b35d0SHolger Eitzenberger lacpdu->partner_port_priority = htons(partner->port_priority);
8263b5b35d0SHolger Eitzenberger lacpdu->partner_port = htons(partner->port_number);
8273b5b35d0SHolger Eitzenberger lacpdu->partner_state = partner->port_state;
8281da177e4SLinus Torvalds
8291da177e4SLinus Torvalds /* lacpdu->reserved_3_2 initialized
8301da177e4SLinus Torvalds * lacpdu->tlv_type_collector_info initialized
8311da177e4SLinus Torvalds * lacpdu->collector_information_length initialized
8321da177e4SLinus Torvalds * collector_max_delay initialized
8331da177e4SLinus Torvalds * reserved_12[12] initialized
8341da177e4SLinus Torvalds * tlv_type_terminator initialized
8351da177e4SLinus Torvalds * terminator_length initialized
8361da177e4SLinus Torvalds * reserved_50[50] initialized
8371da177e4SLinus Torvalds */
8381da177e4SLinus Torvalds }
8391da177e4SLinus Torvalds
8403bf2d28aSVeaceslav Falico /* ================= main 802.3ad protocol code ========================= */
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds /**
8431da177e4SLinus Torvalds * ad_lacpdu_send - send out a lacpdu packet on a given port
8441da177e4SLinus Torvalds * @port: the port we're looking at
8451da177e4SLinus Torvalds *
8461da177e4SLinus Torvalds * Returns: 0 on success
8471da177e4SLinus Torvalds * < 0 on error
8481da177e4SLinus Torvalds */
ad_lacpdu_send(struct port * port)8491da177e4SLinus Torvalds static int ad_lacpdu_send(struct port *port)
8501da177e4SLinus Torvalds {
8511da177e4SLinus Torvalds struct slave *slave = port->slave;
8521da177e4SLinus Torvalds struct sk_buff *skb;
8531da177e4SLinus Torvalds struct lacpdu_header *lacpdu_header;
8541da177e4SLinus Torvalds int length = sizeof(struct lacpdu_header);
8551da177e4SLinus Torvalds
8561da177e4SLinus Torvalds skb = dev_alloc_skb(length);
8577bfc4753SBandan Das if (!skb)
8581da177e4SLinus Torvalds return -ENOMEM;
8591da177e4SLinus Torvalds
860267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_tx);
861949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(slave->bond).stats.lacpdu_tx);
862267c095aSNikolay Aleksandrov
8631da177e4SLinus Torvalds skb->dev = slave->dev;
864459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb);
865b0e380b1SArnaldo Carvalho de Melo skb->network_header = skb->mac_header + ETH_HLEN;
8661da177e4SLinus Torvalds skb->protocol = PKT_TYPE_LACPDU;
8671da177e4SLinus Torvalds skb->priority = TC_PRIO_CONTROL;
8681da177e4SLinus Torvalds
8694df864c1SJohannes Berg lacpdu_header = skb_put(skb, length);
8701da177e4SLinus Torvalds
871ada0f863SJoe Perches ether_addr_copy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr);
872b595076aSUwe Kleine-König /* Note: source address is set to be the member's PERMANENT address,
8733bf2d28aSVeaceslav Falico * because we use it to identify loopback lacpdus in receive.
8743bf2d28aSVeaceslav Falico */
875ada0f863SJoe Perches ether_addr_copy(lacpdu_header->hdr.h_source, slave->perm_hwaddr);
876e727149eSHolger Eitzenberger lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
8771da177e4SLinus Torvalds
8783bf2d28aSVeaceslav Falico lacpdu_header->lacpdu = port->lacpdu;
8791da177e4SLinus Torvalds
8801da177e4SLinus Torvalds dev_queue_xmit(skb);
8811da177e4SLinus Torvalds
8821da177e4SLinus Torvalds return 0;
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds
8851da177e4SLinus Torvalds /**
8861da177e4SLinus Torvalds * ad_marker_send - send marker information/response on a given port
8871da177e4SLinus Torvalds * @port: the port we're looking at
8881da177e4SLinus Torvalds * @marker: marker data to send
8891da177e4SLinus Torvalds *
8901da177e4SLinus Torvalds * Returns: 0 on success
8911da177e4SLinus Torvalds * < 0 on error
8921da177e4SLinus Torvalds */
ad_marker_send(struct port * port,struct bond_marker * marker)8931c3f0b8eSMathieu Desnoyers static int ad_marker_send(struct port *port, struct bond_marker *marker)
8941da177e4SLinus Torvalds {
8951da177e4SLinus Torvalds struct slave *slave = port->slave;
8961da177e4SLinus Torvalds struct sk_buff *skb;
8971c3f0b8eSMathieu Desnoyers struct bond_marker_header *marker_header;
8981c3f0b8eSMathieu Desnoyers int length = sizeof(struct bond_marker_header);
8991da177e4SLinus Torvalds
9001da177e4SLinus Torvalds skb = dev_alloc_skb(length + 16);
9017bfc4753SBandan Das if (!skb)
9021da177e4SLinus Torvalds return -ENOMEM;
9031da177e4SLinus Torvalds
904267c095aSNikolay Aleksandrov switch (marker->tlv_type) {
905267c095aSNikolay Aleksandrov case AD_MARKER_INFORMATION_SUBTYPE:
906267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(slave)->stats.marker_tx);
907949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(slave->bond).stats.marker_tx);
908267c095aSNikolay Aleksandrov break;
909267c095aSNikolay Aleksandrov case AD_MARKER_RESPONSE_SUBTYPE:
910267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(slave)->stats.marker_resp_tx);
911949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(slave->bond).stats.marker_resp_tx);
912267c095aSNikolay Aleksandrov break;
913267c095aSNikolay Aleksandrov }
914267c095aSNikolay Aleksandrov
9151da177e4SLinus Torvalds skb_reserve(skb, 16);
9161da177e4SLinus Torvalds
9171da177e4SLinus Torvalds skb->dev = slave->dev;
918459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb);
919b0e380b1SArnaldo Carvalho de Melo skb->network_header = skb->mac_header + ETH_HLEN;
9201da177e4SLinus Torvalds skb->protocol = PKT_TYPE_LACPDU;
9211da177e4SLinus Torvalds
9224df864c1SJohannes Berg marker_header = skb_put(skb, length);
9231da177e4SLinus Torvalds
924ada0f863SJoe Perches ether_addr_copy(marker_header->hdr.h_dest, lacpdu_mcast_addr);
925b595076aSUwe Kleine-König /* Note: source address is set to be the member's PERMANENT address,
9263bf2d28aSVeaceslav Falico * because we use it to identify loopback MARKERs in receive.
9273bf2d28aSVeaceslav Falico */
928ada0f863SJoe Perches ether_addr_copy(marker_header->hdr.h_source, slave->perm_hwaddr);
929e727149eSHolger Eitzenberger marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
9301da177e4SLinus Torvalds
9313bf2d28aSVeaceslav Falico marker_header->marker = *marker;
9321da177e4SLinus Torvalds
9331da177e4SLinus Torvalds dev_queue_xmit(skb);
9341da177e4SLinus Torvalds
9351da177e4SLinus Torvalds return 0;
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds
9381da177e4SLinus Torvalds /**
9391da177e4SLinus Torvalds * ad_mux_machine - handle a port's mux state machine
9401da177e4SLinus Torvalds * @port: the port we're looking at
941ee637714SMahesh Bandewar * @update_slave_arr: Does slave array need update?
9421da177e4SLinus Torvalds */
ad_mux_machine(struct port * port,bool * update_slave_arr)943ee637714SMahesh Bandewar static void ad_mux_machine(struct port *port, bool *update_slave_arr)
9441da177e4SLinus Torvalds {
9451da177e4SLinus Torvalds mux_states_t last_state;
9461da177e4SLinus Torvalds
9473bf2d28aSVeaceslav Falico /* keep current State Machine state to compare later if it was
9483bf2d28aSVeaceslav Falico * changed
9493bf2d28aSVeaceslav Falico */
9501da177e4SLinus Torvalds last_state = port->sm_mux_state;
9511da177e4SLinus Torvalds
9521da177e4SLinus Torvalds if (port->sm_vars & AD_PORT_BEGIN) {
9533bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_DETACHED;
9541da177e4SLinus Torvalds } else {
9551da177e4SLinus Torvalds switch (port->sm_mux_state) {
9561da177e4SLinus Torvalds case AD_MUX_DETACHED:
9577bfc4753SBandan Das if ((port->sm_vars & AD_PORT_SELECTED)
9587bfc4753SBandan Das || (port->sm_vars & AD_PORT_STANDBY))
9597bfc4753SBandan Das /* if SELECTED or STANDBY */
9603bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_WAITING;
9611da177e4SLinus Torvalds break;
9621da177e4SLinus Torvalds case AD_MUX_WAITING:
9633bf2d28aSVeaceslav Falico /* if SELECTED == FALSE return to DETACH state */
9643bf2d28aSVeaceslav Falico if (!(port->sm_vars & AD_PORT_SELECTED)) {
9651da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_READY_N;
9663bf2d28aSVeaceslav Falico /* in order to withhold the Selection Logic to
9673bf2d28aSVeaceslav Falico * check all ports READY_N value every callback
9683bf2d28aSVeaceslav Falico * cycle to update ready variable, we check
9693bf2d28aSVeaceslav Falico * READY_N and update READY here
9703bf2d28aSVeaceslav Falico */
9711da177e4SLinus Torvalds __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
9723bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_DETACHED;
9731da177e4SLinus Torvalds break;
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds
9763bf2d28aSVeaceslav Falico /* check if the wait_while_timer expired */
9777bfc4753SBandan Das if (port->sm_mux_timer_counter
9787bfc4753SBandan Das && !(--port->sm_mux_timer_counter))
9791da177e4SLinus Torvalds port->sm_vars |= AD_PORT_READY_N;
9801da177e4SLinus Torvalds
9813bf2d28aSVeaceslav Falico /* in order to withhold the selection logic to check
9823bf2d28aSVeaceslav Falico * all ports READY_N value every callback cycle to
9833bf2d28aSVeaceslav Falico * update ready variable, we check READY_N and update
9843bf2d28aSVeaceslav Falico * READY here
9853bf2d28aSVeaceslav Falico */
9861da177e4SLinus Torvalds __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
9871da177e4SLinus Torvalds
9883bf2d28aSVeaceslav Falico /* if the wait_while_timer expired, and the port is
9893bf2d28aSVeaceslav Falico * in READY state, move to ATTACHED state
9903bf2d28aSVeaceslav Falico */
9917bfc4753SBandan Das if ((port->sm_vars & AD_PORT_READY)
9927bfc4753SBandan Das && !port->sm_mux_timer_counter)
9933bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_ATTACHED;
9941da177e4SLinus Torvalds break;
9951da177e4SLinus Torvalds case AD_MUX_ATTACHED:
9963bf2d28aSVeaceslav Falico /* check also if agg_select_timer expired (so the
9973bf2d28aSVeaceslav Falico * edable port will take place only after this timer)
9983bf2d28aSVeaceslav Falico */
9993bf2d28aSVeaceslav Falico if ((port->sm_vars & AD_PORT_SELECTED) &&
1000c1e46990SAndy Roulin (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
10013bf2d28aSVeaceslav Falico !__check_agg_selection_timer(port)) {
100263b46242SWilson Kok if (port->aggregator->is_active)
100363b46242SWilson Kok port->sm_mux_state =
100463b46242SWilson Kok AD_MUX_COLLECTING_DISTRIBUTING;
10053bf2d28aSVeaceslav Falico } else if (!(port->sm_vars & AD_PORT_SELECTED) ||
10063bf2d28aSVeaceslav Falico (port->sm_vars & AD_PORT_STANDBY)) {
10073bf2d28aSVeaceslav Falico /* if UNSELECTED or STANDBY */
10081da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_READY_N;
10093bf2d28aSVeaceslav Falico /* in order to withhold the selection logic to
10103bf2d28aSVeaceslav Falico * check all ports READY_N value every callback
10113bf2d28aSVeaceslav Falico * cycle to update ready variable, we check
10123bf2d28aSVeaceslav Falico * READY_N and update READY here
10133bf2d28aSVeaceslav Falico */
10141da177e4SLinus Torvalds __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
10153bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_DETACHED;
101663b46242SWilson Kok } else if (port->aggregator->is_active) {
101763b46242SWilson Kok port->actor_oper_port_state |=
1018c1e46990SAndy Roulin LACP_STATE_SYNCHRONIZATION;
10191da177e4SLinus Torvalds }
10201da177e4SLinus Torvalds break;
10211da177e4SLinus Torvalds case AD_MUX_COLLECTING_DISTRIBUTING:
10223bf2d28aSVeaceslav Falico if (!(port->sm_vars & AD_PORT_SELECTED) ||
10233bf2d28aSVeaceslav Falico (port->sm_vars & AD_PORT_STANDBY) ||
1024c1e46990SAndy Roulin !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
1025c1e46990SAndy Roulin !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) {
10263bf2d28aSVeaceslav Falico port->sm_mux_state = AD_MUX_ATTACHED;
10271da177e4SLinus Torvalds } else {
10283bf2d28aSVeaceslav Falico /* if port state hasn't changed make
10293bf2d28aSVeaceslav Falico * sure that a collecting distributing
10303bf2d28aSVeaceslav Falico * port in an active aggregator is enabled
10313bf2d28aSVeaceslav Falico */
10321da177e4SLinus Torvalds if (port->aggregator &&
10331da177e4SLinus Torvalds port->aggregator->is_active &&
10341da177e4SLinus Torvalds !__port_is_enabled(port)) {
10351da177e4SLinus Torvalds __enable_port(port);
103623de0d7bSMahesh Bandewar *update_slave_arr = true;
10371da177e4SLinus Torvalds }
10381da177e4SLinus Torvalds }
10391da177e4SLinus Torvalds break;
10403bf2d28aSVeaceslav Falico default:
10411da177e4SLinus Torvalds break;
10421da177e4SLinus Torvalds }
10431da177e4SLinus Torvalds }
10441da177e4SLinus Torvalds
10453bf2d28aSVeaceslav Falico /* check if the state machine was changed */
10461da177e4SLinus Torvalds if (port->sm_mux_state != last_state) {
104717720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
104817720981SJarod Wilson "Mux Machine: Port=%d, Last State=%d, Curr State=%d\n",
104963b46242SWilson Kok port->actor_port_number,
105063b46242SWilson Kok last_state,
1051a4aee5c8SJoe Perches port->sm_mux_state);
10521da177e4SLinus Torvalds switch (port->sm_mux_state) {
10531da177e4SLinus Torvalds case AD_MUX_DETACHED:
1054c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
1055ee637714SMahesh Bandewar ad_disable_collecting_distributing(port,
1056ee637714SMahesh Bandewar update_slave_arr);
1057c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_COLLECTING;
1058c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
1059d238d458SHolger Eitzenberger port->ntt = true;
10601da177e4SLinus Torvalds break;
10611da177e4SLinus Torvalds case AD_MUX_WAITING:
10621da177e4SLinus Torvalds port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
10631da177e4SLinus Torvalds break;
10641da177e4SLinus Torvalds case AD_MUX_ATTACHED:
106563b46242SWilson Kok if (port->aggregator->is_active)
106663b46242SWilson Kok port->actor_oper_port_state |=
1067c1e46990SAndy Roulin LACP_STATE_SYNCHRONIZATION;
106863b46242SWilson Kok else
106963b46242SWilson Kok port->actor_oper_port_state &=
1070c1e46990SAndy Roulin ~LACP_STATE_SYNCHRONIZATION;
1071c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_COLLECTING;
1072c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
1073ee637714SMahesh Bandewar ad_disable_collecting_distributing(port,
1074ee637714SMahesh Bandewar update_slave_arr);
1075d238d458SHolger Eitzenberger port->ntt = true;
10761da177e4SLinus Torvalds break;
10771da177e4SLinus Torvalds case AD_MUX_COLLECTING_DISTRIBUTING:
1078c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_COLLECTING;
1079c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
1080c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1081ee637714SMahesh Bandewar ad_enable_collecting_distributing(port,
1082ee637714SMahesh Bandewar update_slave_arr);
1083d238d458SHolger Eitzenberger port->ntt = true;
10841da177e4SLinus Torvalds break;
10853bf2d28aSVeaceslav Falico default:
10861da177e4SLinus Torvalds break;
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds }
10891da177e4SLinus Torvalds }
10901da177e4SLinus Torvalds
10911da177e4SLinus Torvalds /**
10921da177e4SLinus Torvalds * ad_rx_machine - handle a port's rx State Machine
10931da177e4SLinus Torvalds * @lacpdu: the lacpdu we've received
10941da177e4SLinus Torvalds * @port: the port we're looking at
10951da177e4SLinus Torvalds *
10961da177e4SLinus Torvalds * If lacpdu arrived, stop previous timer (if exists) and set the next state as
10971da177e4SLinus Torvalds * CURRENT. If timer expired set the state machine in the proper state.
10981da177e4SLinus Torvalds * In other cases, this function checks if we need to switch to other state.
10991da177e4SLinus Torvalds */
ad_rx_machine(struct lacpdu * lacpdu,struct port * port)11001da177e4SLinus Torvalds static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
11011da177e4SLinus Torvalds {
11021da177e4SLinus Torvalds rx_states_t last_state;
11031da177e4SLinus Torvalds
11043bf2d28aSVeaceslav Falico /* keep current State Machine state to compare later if it was
11053bf2d28aSVeaceslav Falico * changed
11063bf2d28aSVeaceslav Falico */
11071da177e4SLinus Torvalds last_state = port->sm_rx_state;
11081da177e4SLinus Torvalds
1109949e7ceaSNikolay Aleksandrov if (lacpdu) {
1110267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.lacpdu_rx);
1111949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(port->slave->bond).stats.lacpdu_rx);
1112949e7ceaSNikolay Aleksandrov }
11133bf2d28aSVeaceslav Falico /* check if state machine should change state */
11143bf2d28aSVeaceslav Falico
11153bf2d28aSVeaceslav Falico /* first, check if port was reinitialized */
111614c9551aSMahesh Bandewar if (port->sm_vars & AD_PORT_BEGIN) {
11177bfc4753SBandan Das port->sm_rx_state = AD_RX_INITIALIZE;
1118ef015d72SMahesh Bandewar port->sm_vars |= AD_PORT_CHURNED;
11193bf2d28aSVeaceslav Falico /* check if port is not enabled */
1120ec891c8bSMahesh Bandewar } else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled)
11217bfc4753SBandan Das port->sm_rx_state = AD_RX_PORT_DISABLED;
11223bf2d28aSVeaceslav Falico /* check if new lacpdu arrived */
11233bf2d28aSVeaceslav Falico else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) ||
11243bf2d28aSVeaceslav Falico (port->sm_rx_state == AD_RX_DEFAULTED) ||
11253bf2d28aSVeaceslav Falico (port->sm_rx_state == AD_RX_CURRENT))) {
112614c9551aSMahesh Bandewar if (port->sm_rx_state != AD_RX_CURRENT)
1127ef015d72SMahesh Bandewar port->sm_vars |= AD_PORT_CHURNED;
11283bf2d28aSVeaceslav Falico port->sm_rx_timer_counter = 0;
11291da177e4SLinus Torvalds port->sm_rx_state = AD_RX_CURRENT;
11301da177e4SLinus Torvalds } else {
11313bf2d28aSVeaceslav Falico /* if timer is on, and if it is expired */
11323bf2d28aSVeaceslav Falico if (port->sm_rx_timer_counter &&
11333bf2d28aSVeaceslav Falico !(--port->sm_rx_timer_counter)) {
11341da177e4SLinus Torvalds switch (port->sm_rx_state) {
11351da177e4SLinus Torvalds case AD_RX_EXPIRED:
11363bf2d28aSVeaceslav Falico port->sm_rx_state = AD_RX_DEFAULTED;
11371da177e4SLinus Torvalds break;
11381da177e4SLinus Torvalds case AD_RX_CURRENT:
11393bf2d28aSVeaceslav Falico port->sm_rx_state = AD_RX_EXPIRED;
11401da177e4SLinus Torvalds break;
11413bf2d28aSVeaceslav Falico default:
11421da177e4SLinus Torvalds break;
11431da177e4SLinus Torvalds }
11441da177e4SLinus Torvalds } else {
11453bf2d28aSVeaceslav Falico /* if no lacpdu arrived and no timer is on */
11461da177e4SLinus Torvalds switch (port->sm_rx_state) {
11471da177e4SLinus Torvalds case AD_RX_PORT_DISABLED:
1148ec891c8bSMahesh Bandewar if (port->is_enabled &&
1149ec891c8bSMahesh Bandewar (port->sm_vars & AD_PORT_LACP_ENABLED))
11503bf2d28aSVeaceslav Falico port->sm_rx_state = AD_RX_EXPIRED;
11517bfc4753SBandan Das else if (port->is_enabled
11527bfc4753SBandan Das && ((port->sm_vars
11537bfc4753SBandan Das & AD_PORT_LACP_ENABLED) == 0))
11543bf2d28aSVeaceslav Falico port->sm_rx_state = AD_RX_LACP_DISABLED;
11551da177e4SLinus Torvalds break;
11563bf2d28aSVeaceslav Falico default:
11571da177e4SLinus Torvalds break;
11581da177e4SLinus Torvalds
11591da177e4SLinus Torvalds }
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds
11633bf2d28aSVeaceslav Falico /* check if the State machine was changed or new lacpdu arrived */
11641da177e4SLinus Torvalds if ((port->sm_rx_state != last_state) || (lacpdu)) {
116517720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
116617720981SJarod Wilson "Rx Machine: Port=%d, Last State=%d, Curr State=%d\n",
116763b46242SWilson Kok port->actor_port_number,
116863b46242SWilson Kok last_state,
1169a4aee5c8SJoe Perches port->sm_rx_state);
11701da177e4SLinus Torvalds switch (port->sm_rx_state) {
11711da177e4SLinus Torvalds case AD_RX_INITIALIZE:
1172cb8dda90SJianhua Xie if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS))
11731da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_LACP_ENABLED;
11747bfc4753SBandan Das else
11751da177e4SLinus Torvalds port->sm_vars |= AD_PORT_LACP_ENABLED;
11761da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_SELECTED;
11771da177e4SLinus Torvalds __record_default(port);
1178c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_EXPIRED;
11793bf2d28aSVeaceslav Falico port->sm_rx_state = AD_RX_PORT_DISABLED;
11801da177e4SLinus Torvalds
1181df561f66SGustavo A. R. Silva fallthrough;
11821da177e4SLinus Torvalds case AD_RX_PORT_DISABLED:
11831da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_MATCHED;
11841da177e4SLinus Torvalds break;
11851da177e4SLinus Torvalds case AD_RX_LACP_DISABLED:
11861da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_SELECTED;
11871da177e4SLinus Torvalds __record_default(port);
1188c1e46990SAndy Roulin port->partner_oper.port_state &= ~LACP_STATE_AGGREGATION;
11891da177e4SLinus Torvalds port->sm_vars |= AD_PORT_MATCHED;
1190c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_EXPIRED;
11911da177e4SLinus Torvalds break;
11921da177e4SLinus Torvalds case AD_RX_EXPIRED:
11933bf2d28aSVeaceslav Falico /* Reset of the Synchronization flag (Standard 43.4.12)
11943bf2d28aSVeaceslav Falico * This reset cause to disable this port in the
11953bf2d28aSVeaceslav Falico * COLLECTING_DISTRIBUTING state of the mux machine in
11963bf2d28aSVeaceslav Falico * case of EXPIRED even if LINK_DOWN didn't arrive for
11973bf2d28aSVeaceslav Falico * the port.
11983bf2d28aSVeaceslav Falico */
1199c1e46990SAndy Roulin port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION;
12001da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_MATCHED;
1201c1e46990SAndy Roulin port->partner_oper.port_state |= LACP_STATE_LACP_TIMEOUT;
1202c1e46990SAndy Roulin port->partner_oper.port_state |= LACP_STATE_LACP_ACTIVITY;
12031da177e4SLinus Torvalds port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
1204c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_EXPIRED;
1205ef015d72SMahesh Bandewar port->sm_vars |= AD_PORT_CHURNED;
12061da177e4SLinus Torvalds break;
12071da177e4SLinus Torvalds case AD_RX_DEFAULTED:
12081da177e4SLinus Torvalds __update_default_selected(port);
12091da177e4SLinus Torvalds __record_default(port);
12101da177e4SLinus Torvalds port->sm_vars |= AD_PORT_MATCHED;
1211c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_EXPIRED;
12121da177e4SLinus Torvalds break;
12131da177e4SLinus Torvalds case AD_RX_CURRENT:
1214815117adSdingtianhong /* detect loopback situation */
12153bf2d28aSVeaceslav Falico if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system),
12163bf2d28aSVeaceslav Falico &(port->actor_system))) {
121717720981SJarod Wilson slave_err(port->slave->bond->dev, port->slave->dev, "An illegal loopback occurred on slave\n"
121817720981SJarod Wilson "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n");
12191da177e4SLinus Torvalds return;
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds __update_selected(lacpdu, port);
12221da177e4SLinus Torvalds __update_ntt(lacpdu, port);
12231da177e4SLinus Torvalds __record_pdu(lacpdu, port);
1224c1e46990SAndy Roulin port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & LACP_STATE_LACP_TIMEOUT));
1225c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_EXPIRED;
12261da177e4SLinus Torvalds break;
12273bf2d28aSVeaceslav Falico default:
12281da177e4SLinus Torvalds break;
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds }
12321da177e4SLinus Torvalds
12331da177e4SLinus Torvalds /**
123414c9551aSMahesh Bandewar * ad_churn_machine - handle port churn's state machine
123514c9551aSMahesh Bandewar * @port: the port we're looking at
123614c9551aSMahesh Bandewar *
123714c9551aSMahesh Bandewar */
ad_churn_machine(struct port * port)123814c9551aSMahesh Bandewar static void ad_churn_machine(struct port *port)
123914c9551aSMahesh Bandewar {
1240ef015d72SMahesh Bandewar if (port->sm_vars & AD_PORT_CHURNED) {
1241ef015d72SMahesh Bandewar port->sm_vars &= ~AD_PORT_CHURNED;
124214c9551aSMahesh Bandewar port->sm_churn_actor_state = AD_CHURN_MONITOR;
124314c9551aSMahesh Bandewar port->sm_churn_partner_state = AD_CHURN_MONITOR;
124414c9551aSMahesh Bandewar port->sm_churn_actor_timer_counter =
124514c9551aSMahesh Bandewar __ad_timer_to_ticks(AD_ACTOR_CHURN_TIMER, 0);
124614c9551aSMahesh Bandewar port->sm_churn_partner_timer_counter =
124714c9551aSMahesh Bandewar __ad_timer_to_ticks(AD_PARTNER_CHURN_TIMER, 0);
124814c9551aSMahesh Bandewar return;
124914c9551aSMahesh Bandewar }
125014c9551aSMahesh Bandewar if (port->sm_churn_actor_timer_counter &&
125114c9551aSMahesh Bandewar !(--port->sm_churn_actor_timer_counter) &&
125214c9551aSMahesh Bandewar port->sm_churn_actor_state == AD_CHURN_MONITOR) {
1253c1e46990SAndy Roulin if (port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION) {
125414c9551aSMahesh Bandewar port->sm_churn_actor_state = AD_NO_CHURN;
125514c9551aSMahesh Bandewar } else {
125614c9551aSMahesh Bandewar port->churn_actor_count++;
125714c9551aSMahesh Bandewar port->sm_churn_actor_state = AD_CHURN;
125814c9551aSMahesh Bandewar }
125914c9551aSMahesh Bandewar }
126014c9551aSMahesh Bandewar if (port->sm_churn_partner_timer_counter &&
126114c9551aSMahesh Bandewar !(--port->sm_churn_partner_timer_counter) &&
126214c9551aSMahesh Bandewar port->sm_churn_partner_state == AD_CHURN_MONITOR) {
1263c1e46990SAndy Roulin if (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) {
126414c9551aSMahesh Bandewar port->sm_churn_partner_state = AD_NO_CHURN;
126514c9551aSMahesh Bandewar } else {
126614c9551aSMahesh Bandewar port->churn_partner_count++;
126714c9551aSMahesh Bandewar port->sm_churn_partner_state = AD_CHURN;
126814c9551aSMahesh Bandewar }
126914c9551aSMahesh Bandewar }
127014c9551aSMahesh Bandewar }
127114c9551aSMahesh Bandewar
127214c9551aSMahesh Bandewar /**
12731da177e4SLinus Torvalds * ad_tx_machine - handle a port's tx state machine
12741da177e4SLinus Torvalds * @port: the port we're looking at
12751da177e4SLinus Torvalds */
ad_tx_machine(struct port * port)12761da177e4SLinus Torvalds static void ad_tx_machine(struct port *port)
12771da177e4SLinus Torvalds {
12783bf2d28aSVeaceslav Falico /* check if tx timer expired, to verify that we do not send more than
12793bf2d28aSVeaceslav Falico * 3 packets per second
12803bf2d28aSVeaceslav Falico */
12811da177e4SLinus Torvalds if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) {
12823bf2d28aSVeaceslav Falico /* check if there is something to send */
12831da177e4SLinus Torvalds if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
12841da177e4SLinus Torvalds __update_lacpdu_from_port(port);
1285d238d458SHolger Eitzenberger
12861da177e4SLinus Torvalds if (ad_lacpdu_send(port) >= 0) {
128717720981SJarod Wilson slave_dbg(port->slave->bond->dev,
128817720981SJarod Wilson port->slave->dev,
128917720981SJarod Wilson "Sent LACPDU on port %d\n",
1290a4aee5c8SJoe Perches port->actor_port_number);
1291d238d458SHolger Eitzenberger
12923bf2d28aSVeaceslav Falico /* mark ntt as false, so it will not be sent
12933bf2d28aSVeaceslav Falico * again until demanded
12943bf2d28aSVeaceslav Falico */
1295d238d458SHolger Eitzenberger port->ntt = false;
12961da177e4SLinus Torvalds }
12971da177e4SLinus Torvalds }
12983bf2d28aSVeaceslav Falico /* restart tx timer(to verify that we will not exceed
12993bf2d28aSVeaceslav Falico * AD_MAX_TX_IN_SECOND
13003bf2d28aSVeaceslav Falico */
13013bf2d28aSVeaceslav Falico port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
13021da177e4SLinus Torvalds }
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds
13051da177e4SLinus Torvalds /**
13061da177e4SLinus Torvalds * ad_periodic_machine - handle a port's periodic state machine
13071da177e4SLinus Torvalds * @port: the port we're looking at
13083a755cd8SHangbin Liu * @bond_params: bond parameters we will use
13091da177e4SLinus Torvalds *
13101da177e4SLinus Torvalds * Turn ntt flag on priodically to perform periodic transmission of lacpdu's.
13111da177e4SLinus Torvalds */
ad_periodic_machine(struct port * port,struct bond_params * bond_params)1312bbef56d8SColin Ian King static void ad_periodic_machine(struct port *port, struct bond_params *bond_params)
13131da177e4SLinus Torvalds {
13141da177e4SLinus Torvalds periodic_states_t last_state;
13151da177e4SLinus Torvalds
13163bf2d28aSVeaceslav Falico /* keep current state machine state to compare later if it was changed */
13171da177e4SLinus Torvalds last_state = port->sm_periodic_state;
13181da177e4SLinus Torvalds
13193bf2d28aSVeaceslav Falico /* check if port was reinitialized */
13201da177e4SLinus Torvalds if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
13213a755cd8SHangbin Liu (!(port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & LACP_STATE_LACP_ACTIVITY)) ||
1322bbef56d8SColin Ian King !bond_params->lacp_active) {
13233bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_NO_PERIODIC;
13241da177e4SLinus Torvalds }
13253bf2d28aSVeaceslav Falico /* check if state machine should change state */
13261da177e4SLinus Torvalds else if (port->sm_periodic_timer_counter) {
13273bf2d28aSVeaceslav Falico /* check if periodic state machine expired */
13281da177e4SLinus Torvalds if (!(--port->sm_periodic_timer_counter)) {
13293bf2d28aSVeaceslav Falico /* if expired then do tx */
13303bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_PERIODIC_TX;
13311da177e4SLinus Torvalds } else {
13323bf2d28aSVeaceslav Falico /* If not expired, check if there is some new timeout
13333bf2d28aSVeaceslav Falico * parameter from the partner state
13343bf2d28aSVeaceslav Falico */
13351da177e4SLinus Torvalds switch (port->sm_periodic_state) {
13361da177e4SLinus Torvalds case AD_FAST_PERIODIC:
13377bfc4753SBandan Das if (!(port->partner_oper.port_state
1338c1e46990SAndy Roulin & LACP_STATE_LACP_TIMEOUT))
13393bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_SLOW_PERIODIC;
13401da177e4SLinus Torvalds break;
13411da177e4SLinus Torvalds case AD_SLOW_PERIODIC:
1342c1e46990SAndy Roulin if ((port->partner_oper.port_state & LACP_STATE_LACP_TIMEOUT)) {
13431da177e4SLinus Torvalds port->sm_periodic_timer_counter = 0;
13443bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_PERIODIC_TX;
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds break;
13473bf2d28aSVeaceslav Falico default:
13481da177e4SLinus Torvalds break;
13491da177e4SLinus Torvalds }
13501da177e4SLinus Torvalds }
13511da177e4SLinus Torvalds } else {
13521da177e4SLinus Torvalds switch (port->sm_periodic_state) {
13531da177e4SLinus Torvalds case AD_NO_PERIODIC:
13543bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_FAST_PERIODIC;
13551da177e4SLinus Torvalds break;
13561da177e4SLinus Torvalds case AD_PERIODIC_TX:
13573bf2d28aSVeaceslav Falico if (!(port->partner_oper.port_state &
1358c1e46990SAndy Roulin LACP_STATE_LACP_TIMEOUT))
13593bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_SLOW_PERIODIC;
13607bfc4753SBandan Das else
13613bf2d28aSVeaceslav Falico port->sm_periodic_state = AD_FAST_PERIODIC;
13621da177e4SLinus Torvalds break;
13633bf2d28aSVeaceslav Falico default:
13641da177e4SLinus Torvalds break;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds
13683bf2d28aSVeaceslav Falico /* check if the state machine was changed */
13691da177e4SLinus Torvalds if (port->sm_periodic_state != last_state) {
137017720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
137117720981SJarod Wilson "Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n",
1372a4aee5c8SJoe Perches port->actor_port_number, last_state,
1373a4aee5c8SJoe Perches port->sm_periodic_state);
13741da177e4SLinus Torvalds switch (port->sm_periodic_state) {
13751da177e4SLinus Torvalds case AD_NO_PERIODIC:
13763bf2d28aSVeaceslav Falico port->sm_periodic_timer_counter = 0;
13771da177e4SLinus Torvalds break;
13781da177e4SLinus Torvalds case AD_FAST_PERIODIC:
13793bf2d28aSVeaceslav Falico /* decrement 1 tick we lost in the PERIODIC_TX cycle */
13803bf2d28aSVeaceslav Falico port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1;
13811da177e4SLinus Torvalds break;
13821da177e4SLinus Torvalds case AD_SLOW_PERIODIC:
13833bf2d28aSVeaceslav Falico /* decrement 1 tick we lost in the PERIODIC_TX cycle */
13843bf2d28aSVeaceslav Falico port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1;
13851da177e4SLinus Torvalds break;
13861da177e4SLinus Torvalds case AD_PERIODIC_TX:
1387d238d458SHolger Eitzenberger port->ntt = true;
13881da177e4SLinus Torvalds break;
13893bf2d28aSVeaceslav Falico default:
13901da177e4SLinus Torvalds break;
13911da177e4SLinus Torvalds }
13921da177e4SLinus Torvalds }
13931da177e4SLinus Torvalds }
13941da177e4SLinus Torvalds
13951da177e4SLinus Torvalds /**
13961da177e4SLinus Torvalds * ad_port_selection_logic - select aggregation groups
13971da177e4SLinus Torvalds * @port: the port we're looking at
1398ee637714SMahesh Bandewar * @update_slave_arr: Does slave array need update?
13991da177e4SLinus Torvalds *
14001da177e4SLinus Torvalds * Select aggregation groups, and assign each port for it's aggregetor. The
14011da177e4SLinus Torvalds * selection logic is called in the inititalization (after all the handshkes),
14021da177e4SLinus Torvalds * and after every lacpdu receive (if selected is off).
14031da177e4SLinus Torvalds */
ad_port_selection_logic(struct port * port,bool * update_slave_arr)1404ee637714SMahesh Bandewar static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
14051da177e4SLinus Torvalds {
14061da177e4SLinus Torvalds struct aggregator *aggregator, *free_aggregator = NULL, *temp_aggregator;
14071da177e4SLinus Torvalds struct port *last_port = NULL, *curr_port;
14083e36bb75SVeaceslav Falico struct list_head *iter;
14093e36bb75SVeaceslav Falico struct bonding *bond;
14103e36bb75SVeaceslav Falico struct slave *slave;
14111da177e4SLinus Torvalds int found = 0;
14121da177e4SLinus Torvalds
14133bf2d28aSVeaceslav Falico /* if the port is already Selected, do nothing */
14147bfc4753SBandan Das if (port->sm_vars & AD_PORT_SELECTED)
14151da177e4SLinus Torvalds return;
14161da177e4SLinus Torvalds
14173e36bb75SVeaceslav Falico bond = __get_bond_by_port(port);
14183e36bb75SVeaceslav Falico
14193bf2d28aSVeaceslav Falico /* if the port is connected to other aggregator, detach it */
14201da177e4SLinus Torvalds if (port->aggregator) {
14213bf2d28aSVeaceslav Falico /* detach the port from its former aggregator */
14221da177e4SLinus Torvalds temp_aggregator = port->aggregator;
1423128ea6c3SBandan Das for (curr_port = temp_aggregator->lag_ports; curr_port;
1424128ea6c3SBandan Das last_port = curr_port,
1425128ea6c3SBandan Das curr_port = curr_port->next_port_in_aggregator) {
14261da177e4SLinus Torvalds if (curr_port == port) {
14271da177e4SLinus Torvalds temp_aggregator->num_of_ports--;
14283bf2d28aSVeaceslav Falico /* if it is the first port attached to the
14293bf2d28aSVeaceslav Falico * aggregator
14303bf2d28aSVeaceslav Falico */
14313bf2d28aSVeaceslav Falico if (!last_port) {
1432128ea6c3SBandan Das temp_aggregator->lag_ports =
1433128ea6c3SBandan Das port->next_port_in_aggregator;
14343bf2d28aSVeaceslav Falico } else {
14353bf2d28aSVeaceslav Falico /* not the first port attached to the
14363bf2d28aSVeaceslav Falico * aggregator
14373bf2d28aSVeaceslav Falico */
1438128ea6c3SBandan Das last_port->next_port_in_aggregator =
1439128ea6c3SBandan Das port->next_port_in_aggregator;
14401da177e4SLinus Torvalds }
14411da177e4SLinus Torvalds
14423bf2d28aSVeaceslav Falico /* clear the port's relations to this
14433bf2d28aSVeaceslav Falico * aggregator
14443bf2d28aSVeaceslav Falico */
14451da177e4SLinus Torvalds port->aggregator = NULL;
14461da177e4SLinus Torvalds port->next_port_in_aggregator = NULL;
14471da177e4SLinus Torvalds port->actor_port_aggregator_identifier = 0;
14481da177e4SLinus Torvalds
144917720981SJarod Wilson slave_dbg(bond->dev, port->slave->dev, "Port %d left LAG %d\n",
1450a4aee5c8SJoe Perches port->actor_port_number,
1451a4aee5c8SJoe Perches temp_aggregator->aggregator_identifier);
14523bf2d28aSVeaceslav Falico /* if the aggregator is empty, clear its
14533bf2d28aSVeaceslav Falico * parameters, and set it ready to be attached
14543bf2d28aSVeaceslav Falico */
14557bfc4753SBandan Das if (!temp_aggregator->lag_ports)
14561da177e4SLinus Torvalds ad_clear_agg(temp_aggregator);
14571da177e4SLinus Torvalds break;
14581da177e4SLinus Torvalds }
14591da177e4SLinus Torvalds }
14603bf2d28aSVeaceslav Falico if (!curr_port) {
14613bf2d28aSVeaceslav Falico /* meaning: the port was related to an aggregator
14623bf2d28aSVeaceslav Falico * but was not on the aggregator port list
14633bf2d28aSVeaceslav Falico */
146417720981SJarod Wilson net_warn_ratelimited("%s: (slave %s): Warning: Port %d was related to aggregator %d but was not on its port list\n",
1465471cb5a3SJiri Pirko port->slave->bond->dev->name,
1466e5e2a8fdSJiri Pirko port->slave->dev->name,
146717720981SJarod Wilson port->actor_port_number,
14681da177e4SLinus Torvalds port->aggregator->aggregator_identifier);
14691da177e4SLinus Torvalds }
14701da177e4SLinus Torvalds }
14713bf2d28aSVeaceslav Falico /* search on all aggregators for a suitable aggregator for this port */
14723e36bb75SVeaceslav Falico bond_for_each_slave(bond, slave, iter) {
14733fdddd85Sdingtianhong aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
14741da177e4SLinus Torvalds
14753bf2d28aSVeaceslav Falico /* keep a free aggregator for later use(if needed) */
14761da177e4SLinus Torvalds if (!aggregator->lag_ports) {
14777bfc4753SBandan Das if (!free_aggregator)
14781da177e4SLinus Torvalds free_aggregator = aggregator;
14791da177e4SLinus Torvalds continue;
14801da177e4SLinus Torvalds }
1481815117adSdingtianhong /* check if current aggregator suits us */
1482815117adSdingtianhong if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && /* if all parameters match AND */
1483815117adSdingtianhong MAC_ADDRESS_EQUAL(&(aggregator->partner_system), &(port->partner_oper.system)) &&
14841055c9abSHolger Eitzenberger (aggregator->partner_system_priority == port->partner_oper.system_priority) &&
14851055c9abSHolger Eitzenberger (aggregator->partner_oper_aggregator_key == port->partner_oper.key)
14861da177e4SLinus Torvalds ) &&
1487815117adSdingtianhong ((!MAC_ADDRESS_EQUAL(&(port->partner_oper.system), &(null_mac_addr)) && /* partner answers */
1488815117adSdingtianhong !aggregator->is_individual) /* but is not individual OR */
14891da177e4SLinus Torvalds )
14901da177e4SLinus Torvalds ) {
1491815117adSdingtianhong /* attach to the founded aggregator */
14921da177e4SLinus Torvalds port->aggregator = aggregator;
1493128ea6c3SBandan Das port->actor_port_aggregator_identifier =
1494128ea6c3SBandan Das port->aggregator->aggregator_identifier;
14951da177e4SLinus Torvalds port->next_port_in_aggregator = aggregator->lag_ports;
14961da177e4SLinus Torvalds port->aggregator->num_of_ports++;
14971da177e4SLinus Torvalds aggregator->lag_ports = port;
149817720981SJarod Wilson slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n",
1499a4aee5c8SJoe Perches port->actor_port_number,
1500a4aee5c8SJoe Perches port->aggregator->aggregator_identifier);
15011da177e4SLinus Torvalds
15023bf2d28aSVeaceslav Falico /* mark this port as selected */
15031da177e4SLinus Torvalds port->sm_vars |= AD_PORT_SELECTED;
15041da177e4SLinus Torvalds found = 1;
15051da177e4SLinus Torvalds break;
15061da177e4SLinus Torvalds }
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds
15093bf2d28aSVeaceslav Falico /* the port couldn't find an aggregator - attach it to a new
15103bf2d28aSVeaceslav Falico * aggregator
15113bf2d28aSVeaceslav Falico */
15121da177e4SLinus Torvalds if (!found) {
15131da177e4SLinus Torvalds if (free_aggregator) {
15143bf2d28aSVeaceslav Falico /* assign port a new aggregator */
15151da177e4SLinus Torvalds port->aggregator = free_aggregator;
1516128ea6c3SBandan Das port->actor_port_aggregator_identifier =
1517128ea6c3SBandan Das port->aggregator->aggregator_identifier;
15181da177e4SLinus Torvalds
15193bf2d28aSVeaceslav Falico /* update the new aggregator's parameters
15203bf2d28aSVeaceslav Falico * if port was responsed from the end-user
15213bf2d28aSVeaceslav Falico */
1522cb8dda90SJianhua Xie if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
15237bfc4753SBandan Das /* if port is full duplex */
15241624db7bSHolger Eitzenberger port->aggregator->is_individual = false;
15257bfc4753SBandan Das else
15261624db7bSHolger Eitzenberger port->aggregator->is_individual = true;
15271da177e4SLinus Torvalds
1528c3cd9ee1SMahesh Bandewar port->aggregator->actor_admin_aggregator_key =
1529c3cd9ee1SMahesh Bandewar port->actor_admin_port_key;
1530c3cd9ee1SMahesh Bandewar port->aggregator->actor_oper_aggregator_key =
1531c3cd9ee1SMahesh Bandewar port->actor_oper_port_key;
1532128ea6c3SBandan Das port->aggregator->partner_system =
1533128ea6c3SBandan Das port->partner_oper.system;
1534128ea6c3SBandan Das port->aggregator->partner_system_priority =
1535128ea6c3SBandan Das port->partner_oper.system_priority;
15361055c9abSHolger Eitzenberger port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
15371da177e4SLinus Torvalds port->aggregator->receive_state = 1;
15381da177e4SLinus Torvalds port->aggregator->transmit_state = 1;
15391da177e4SLinus Torvalds port->aggregator->lag_ports = port;
15401da177e4SLinus Torvalds port->aggregator->num_of_ports++;
15411da177e4SLinus Torvalds
15423bf2d28aSVeaceslav Falico /* mark this port as selected */
15431da177e4SLinus Torvalds port->sm_vars |= AD_PORT_SELECTED;
15441da177e4SLinus Torvalds
154517720981SJarod Wilson slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n",
1546a4aee5c8SJoe Perches port->actor_port_number,
1547a4aee5c8SJoe Perches port->aggregator->aggregator_identifier);
15481da177e4SLinus Torvalds } else {
154917720981SJarod Wilson slave_err(bond->dev, port->slave->dev,
155017720981SJarod Wilson "Port %d did not find a suitable aggregator\n",
155117720981SJarod Wilson port->actor_port_number);
1552*9c807965SDaniil Tatianin return;
15531da177e4SLinus Torvalds }
15541da177e4SLinus Torvalds }
15553bf2d28aSVeaceslav Falico /* if all aggregator's ports are READY_N == TRUE, set ready=TRUE
15563bf2d28aSVeaceslav Falico * in all aggregator's ports, else set ready=FALSE in all
15573bf2d28aSVeaceslav Falico * aggregator's ports
15583bf2d28aSVeaceslav Falico */
15593bf2d28aSVeaceslav Falico __set_agg_ports_ready(port->aggregator,
15603bf2d28aSVeaceslav Falico __agg_ports_are_ready(port->aggregator));
15611da177e4SLinus Torvalds
1562fd989c83SJay Vosburgh aggregator = __get_first_agg(port);
1563ee637714SMahesh Bandewar ad_agg_selection_logic(aggregator, update_slave_arr);
156463b46242SWilson Kok
156563b46242SWilson Kok if (!port->aggregator->is_active)
1566c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
15671da177e4SLinus Torvalds }
1568fd989c83SJay Vosburgh
15693bf2d28aSVeaceslav Falico /* Decide if "agg" is a better choice for the new active aggregator that
1570fd989c83SJay Vosburgh * the current best, according to the ad_select policy.
1571fd989c83SJay Vosburgh */
ad_agg_selection_test(struct aggregator * best,struct aggregator * curr)1572fd989c83SJay Vosburgh static struct aggregator *ad_agg_selection_test(struct aggregator *best,
1573fd989c83SJay Vosburgh struct aggregator *curr)
1574fd989c83SJay Vosburgh {
15753bf2d28aSVeaceslav Falico /* 0. If no best, select current.
1576fd989c83SJay Vosburgh *
1577fd989c83SJay Vosburgh * 1. If the current agg is not individual, and the best is
1578fd989c83SJay Vosburgh * individual, select current.
1579fd989c83SJay Vosburgh *
1580fd989c83SJay Vosburgh * 2. If current agg is individual and the best is not, keep best.
1581fd989c83SJay Vosburgh *
1582fd989c83SJay Vosburgh * 3. Therefore, current and best are both individual or both not
1583fd989c83SJay Vosburgh * individual, so:
1584fd989c83SJay Vosburgh *
1585fd989c83SJay Vosburgh * 3a. If current agg partner replied, and best agg partner did not,
1586fd989c83SJay Vosburgh * select current.
1587fd989c83SJay Vosburgh *
1588fd989c83SJay Vosburgh * 3b. If current agg partner did not reply and best agg partner
1589fd989c83SJay Vosburgh * did reply, keep best.
1590fd989c83SJay Vosburgh *
1591fd989c83SJay Vosburgh * 4. Therefore, current and best both have partner replies or
1592fd989c83SJay Vosburgh * both do not, so perform selection policy:
1593fd989c83SJay Vosburgh *
1594fd989c83SJay Vosburgh * BOND_AD_COUNT: Select by count of ports. If count is equal,
1595fd989c83SJay Vosburgh * select by bandwidth.
1596fd989c83SJay Vosburgh *
1597fd989c83SJay Vosburgh * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth.
1598fd989c83SJay Vosburgh */
1599fd989c83SJay Vosburgh if (!best)
1600fd989c83SJay Vosburgh return curr;
1601fd989c83SJay Vosburgh
1602fd989c83SJay Vosburgh if (!curr->is_individual && best->is_individual)
1603fd989c83SJay Vosburgh return curr;
1604fd989c83SJay Vosburgh
1605fd989c83SJay Vosburgh if (curr->is_individual && !best->is_individual)
1606fd989c83SJay Vosburgh return best;
1607fd989c83SJay Vosburgh
1608fd989c83SJay Vosburgh if (__agg_has_partner(curr) && !__agg_has_partner(best))
1609fd989c83SJay Vosburgh return curr;
1610fd989c83SJay Vosburgh
1611fd989c83SJay Vosburgh if (!__agg_has_partner(curr) && __agg_has_partner(best))
1612fd989c83SJay Vosburgh return best;
1613fd989c83SJay Vosburgh
1614fd989c83SJay Vosburgh switch (__get_agg_selection_mode(curr->lag_ports)) {
1615fd989c83SJay Vosburgh case BOND_AD_COUNT:
16160622cab0SJay Vosburgh if (__agg_active_ports(curr) > __agg_active_ports(best))
1617fd989c83SJay Vosburgh return curr;
1618fd989c83SJay Vosburgh
16190622cab0SJay Vosburgh if (__agg_active_ports(curr) < __agg_active_ports(best))
1620fd989c83SJay Vosburgh return best;
1621fd989c83SJay Vosburgh
1622df561f66SGustavo A. R. Silva fallthrough;
1623fd989c83SJay Vosburgh case BOND_AD_STABLE:
1624fd989c83SJay Vosburgh case BOND_AD_BANDWIDTH:
1625fd989c83SJay Vosburgh if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best))
1626fd989c83SJay Vosburgh return curr;
1627fd989c83SJay Vosburgh
1628fd989c83SJay Vosburgh break;
1629fd989c83SJay Vosburgh
1630fd989c83SJay Vosburgh default:
163117720981SJarod Wilson net_warn_ratelimited("%s: (slave %s): Impossible agg select mode %d\n",
1632471cb5a3SJiri Pirko curr->slave->bond->dev->name,
163317720981SJarod Wilson curr->slave->dev->name,
1634fd989c83SJay Vosburgh __get_agg_selection_mode(curr->lag_ports));
1635fd989c83SJay Vosburgh break;
1636fd989c83SJay Vosburgh }
1637fd989c83SJay Vosburgh
1638fd989c83SJay Vosburgh return best;
16391da177e4SLinus Torvalds }
16401da177e4SLinus Torvalds
agg_device_up(const struct aggregator * agg)16414cd6fe1cSStephen Hemminger static int agg_device_up(const struct aggregator *agg)
16424cd6fe1cSStephen Hemminger {
16432430af8bSJiri Bohac struct port *port = agg->lag_ports;
16443bf2d28aSVeaceslav Falico
16452430af8bSJiri Bohac if (!port)
16462430af8bSJiri Bohac return 0;
16473bf2d28aSVeaceslav Falico
16480622cab0SJay Vosburgh for (port = agg->lag_ports; port;
16490622cab0SJay Vosburgh port = port->next_port_in_aggregator) {
16500622cab0SJay Vosburgh if (netif_running(port->slave->dev) &&
16510622cab0SJay Vosburgh netif_carrier_ok(port->slave->dev))
16520622cab0SJay Vosburgh return 1;
16530622cab0SJay Vosburgh }
16540622cab0SJay Vosburgh
16550622cab0SJay Vosburgh return 0;
16564cd6fe1cSStephen Hemminger }
16574cd6fe1cSStephen Hemminger
16581da177e4SLinus Torvalds /**
16591da177e4SLinus Torvalds * ad_agg_selection_logic - select an aggregation group for a team
1660a35e5478SLee Jones * @agg: the aggregator we're looking at
1661ee637714SMahesh Bandewar * @update_slave_arr: Does slave array need update?
16621da177e4SLinus Torvalds *
16631da177e4SLinus Torvalds * It is assumed that only one aggregator may be selected for a team.
1664fd989c83SJay Vosburgh *
1665fd989c83SJay Vosburgh * The logic of this function is to select the aggregator according to
1666fd989c83SJay Vosburgh * the ad_select policy:
1667fd989c83SJay Vosburgh *
1668fd989c83SJay Vosburgh * BOND_AD_STABLE: select the aggregator with the most ports attached to
1669fd989c83SJay Vosburgh * it, and to reselect the active aggregator only if the previous
1670fd989c83SJay Vosburgh * aggregator has no more ports related to it.
1671fd989c83SJay Vosburgh *
1672fd989c83SJay Vosburgh * BOND_AD_BANDWIDTH: select the aggregator with the highest total
1673fd989c83SJay Vosburgh * bandwidth, and reselect whenever a link state change takes place or the
1674fd989c83SJay Vosburgh * set of slaves in the bond changes.
1675fd989c83SJay Vosburgh *
1676fd989c83SJay Vosburgh * BOND_AD_COUNT: select the aggregator with largest number of ports
1677fd989c83SJay Vosburgh * (slaves), and reselect whenever a link state change takes place or the
1678fd989c83SJay Vosburgh * set of slaves in the bond changes.
16791da177e4SLinus Torvalds *
16801da177e4SLinus Torvalds * FIXME: this function MUST be called with the first agg in the bond, or
16811da177e4SLinus Torvalds * __get_active_agg() won't work correctly. This function should be better
16821da177e4SLinus Torvalds * called with the bond itself, and retrieve the first agg from it.
16831da177e4SLinus Torvalds */
ad_agg_selection_logic(struct aggregator * agg,bool * update_slave_arr)1684ee637714SMahesh Bandewar static void ad_agg_selection_logic(struct aggregator *agg,
1685ee637714SMahesh Bandewar bool *update_slave_arr)
16861da177e4SLinus Torvalds {
1687fd989c83SJay Vosburgh struct aggregator *best, *active, *origin;
1688bef1fcceSVeaceslav Falico struct bonding *bond = agg->slave->bond;
1689bef1fcceSVeaceslav Falico struct list_head *iter;
1690bef1fcceSVeaceslav Falico struct slave *slave;
16911da177e4SLinus Torvalds struct port *port;
16921da177e4SLinus Torvalds
169349b7624eSVeaceslav Falico rcu_read_lock();
1694fd989c83SJay Vosburgh origin = agg;
1695fd989c83SJay Vosburgh active = __get_active_agg(agg);
16964cd6fe1cSStephen Hemminger best = (active && agg_device_up(active)) ? active : NULL;
16971da177e4SLinus Torvalds
1698be79bd04Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter) {
16993fdddd85Sdingtianhong agg = &(SLAVE_AD_INFO(slave)->aggregator);
1700bef1fcceSVeaceslav Falico
1701fd989c83SJay Vosburgh agg->is_active = 0;
17021da177e4SLinus Torvalds
17030622cab0SJay Vosburgh if (__agg_active_ports(agg) && agg_device_up(agg))
1704fd989c83SJay Vosburgh best = ad_agg_selection_test(best, agg);
1705bef1fcceSVeaceslav Falico }
17061da177e4SLinus Torvalds
1707fd989c83SJay Vosburgh if (best &&
1708fd989c83SJay Vosburgh __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) {
17093bf2d28aSVeaceslav Falico /* For the STABLE policy, don't replace the old active
1710fd989c83SJay Vosburgh * aggregator if it's still active (it has an answering
1711fd989c83SJay Vosburgh * partner) or if both the best and active don't have an
1712fd989c83SJay Vosburgh * answering partner.
1713fd989c83SJay Vosburgh */
1714fd989c83SJay Vosburgh if (active && active->lag_ports &&
17150622cab0SJay Vosburgh __agg_active_ports(active) &&
1716fd989c83SJay Vosburgh (__agg_has_partner(active) ||
17173bf2d28aSVeaceslav Falico (!__agg_has_partner(active) &&
17183bf2d28aSVeaceslav Falico !__agg_has_partner(best)))) {
1719fd989c83SJay Vosburgh if (!(!active->actor_oper_aggregator_key &&
1720fd989c83SJay Vosburgh best->actor_oper_aggregator_key)) {
1721fd989c83SJay Vosburgh best = NULL;
1722fd989c83SJay Vosburgh active->is_active = 1;
17231da177e4SLinus Torvalds }
17241da177e4SLinus Torvalds }
17251da177e4SLinus Torvalds }
17261da177e4SLinus Torvalds
1727fd989c83SJay Vosburgh if (best && (best == active)) {
1728fd989c83SJay Vosburgh best = NULL;
1729fd989c83SJay Vosburgh active->is_active = 1;
1730fd989c83SJay Vosburgh }
1731fd989c83SJay Vosburgh
1732be79bd04Sdingtianhong /* if there is new best aggregator, activate it */
1733fd989c83SJay Vosburgh if (best) {
173417720981SJarod Wilson netdev_dbg(bond->dev, "(slave %s): best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
173517720981SJarod Wilson best->slave ? best->slave->dev->name : "NULL",
1736fd989c83SJay Vosburgh best->aggregator_identifier, best->num_of_ports,
1737fd989c83SJay Vosburgh best->actor_oper_aggregator_key,
1738fd989c83SJay Vosburgh best->partner_oper_aggregator_key,
1739fd989c83SJay Vosburgh best->is_individual, best->is_active);
174017720981SJarod Wilson netdev_dbg(bond->dev, "(slave %s): best ports %p slave %p\n",
174117720981SJarod Wilson best->slave ? best->slave->dev->name : "NULL",
174217720981SJarod Wilson best->lag_ports, best->slave);
17431da177e4SLinus Torvalds
1744be79bd04Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter) {
17453fdddd85Sdingtianhong agg = &(SLAVE_AD_INFO(slave)->aggregator);
1746fd989c83SJay Vosburgh
174717720981SJarod Wilson slave_dbg(bond->dev, slave->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
1748fd989c83SJay Vosburgh agg->aggregator_identifier, agg->num_of_ports,
1749fd989c83SJay Vosburgh agg->actor_oper_aggregator_key,
1750fd989c83SJay Vosburgh agg->partner_oper_aggregator_key,
1751fd989c83SJay Vosburgh agg->is_individual, agg->is_active);
17521da177e4SLinus Torvalds }
17531da177e4SLinus Torvalds
175417720981SJarod Wilson /* check if any partner replies */
175517720981SJarod Wilson if (best->is_individual)
1756d4471f5eSVeaceslav Falico net_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
175717720981SJarod Wilson bond->dev->name);
17581da177e4SLinus Torvalds
1759fd989c83SJay Vosburgh best->is_active = 1;
176017720981SJarod Wilson netdev_dbg(bond->dev, "(slave %s): LAG %d chosen as the active LAG\n",
176117720981SJarod Wilson best->slave ? best->slave->dev->name : "NULL",
1762fd989c83SJay Vosburgh best->aggregator_identifier);
176317720981SJarod Wilson netdev_dbg(bond->dev, "(slave %s): Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
176417720981SJarod Wilson best->slave ? best->slave->dev->name : "NULL",
1765fd989c83SJay Vosburgh best->aggregator_identifier, best->num_of_ports,
1766fd989c83SJay Vosburgh best->actor_oper_aggregator_key,
1767fd989c83SJay Vosburgh best->partner_oper_aggregator_key,
1768fd989c83SJay Vosburgh best->is_individual, best->is_active);
17691da177e4SLinus Torvalds
17703bf2d28aSVeaceslav Falico /* disable the ports that were related to the former
17713bf2d28aSVeaceslav Falico * active_aggregator
17723bf2d28aSVeaceslav Falico */
1773fd989c83SJay Vosburgh if (active) {
1774fd989c83SJay Vosburgh for (port = active->lag_ports; port;
1775fd989c83SJay Vosburgh port = port->next_port_in_aggregator) {
17761da177e4SLinus Torvalds __disable_port(port);
17771da177e4SLinus Torvalds }
17781da177e4SLinus Torvalds }
1779ee637714SMahesh Bandewar /* Slave array needs update. */
1780ee637714SMahesh Bandewar *update_slave_arr = true;
17811da177e4SLinus Torvalds }
17821da177e4SLinus Torvalds
17833bf2d28aSVeaceslav Falico /* if the selected aggregator is of join individuals
1784fd989c83SJay Vosburgh * (partner_system is NULL), enable their ports
1785fd989c83SJay Vosburgh */
1786fd989c83SJay Vosburgh active = __get_active_agg(origin);
17871da177e4SLinus Torvalds
1788fd989c83SJay Vosburgh if (active) {
1789fd989c83SJay Vosburgh if (!__agg_has_partner(active)) {
1790fd989c83SJay Vosburgh for (port = active->lag_ports; port;
1791fd989c83SJay Vosburgh port = port->next_port_in_aggregator) {
17921da177e4SLinus Torvalds __enable_port(port);
17931da177e4SLinus Torvalds }
179423de0d7bSMahesh Bandewar *update_slave_arr = true;
17951da177e4SLinus Torvalds }
17961da177e4SLinus Torvalds }
1797fd989c83SJay Vosburgh
1798be79bd04Sdingtianhong rcu_read_unlock();
1799be79bd04Sdingtianhong
1800fd989c83SJay Vosburgh bond_3ad_set_carrier(bond);
1801fd989c83SJay Vosburgh }
18021da177e4SLinus Torvalds
18031da177e4SLinus Torvalds /**
18041da177e4SLinus Torvalds * ad_clear_agg - clear a given aggregator's parameters
18051da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
18061da177e4SLinus Torvalds */
ad_clear_agg(struct aggregator * aggregator)18071da177e4SLinus Torvalds static void ad_clear_agg(struct aggregator *aggregator)
18081da177e4SLinus Torvalds {
18091da177e4SLinus Torvalds if (aggregator) {
18101624db7bSHolger Eitzenberger aggregator->is_individual = false;
18111da177e4SLinus Torvalds aggregator->actor_admin_aggregator_key = 0;
18121da177e4SLinus Torvalds aggregator->actor_oper_aggregator_key = 0;
1813f87fda00SEric Dumazet eth_zero_addr(aggregator->partner_system.mac_addr_value);
18141da177e4SLinus Torvalds aggregator->partner_system_priority = 0;
18151da177e4SLinus Torvalds aggregator->partner_oper_aggregator_key = 0;
18161da177e4SLinus Torvalds aggregator->receive_state = 0;
18171da177e4SLinus Torvalds aggregator->transmit_state = 0;
18181da177e4SLinus Torvalds aggregator->lag_ports = NULL;
18191da177e4SLinus Torvalds aggregator->is_active = 0;
18201da177e4SLinus Torvalds aggregator->num_of_ports = 0;
182117720981SJarod Wilson pr_debug("%s: LAG %d was cleared\n",
182217720981SJarod Wilson aggregator->slave ?
182317720981SJarod Wilson aggregator->slave->dev->name : "NULL",
1824a4aee5c8SJoe Perches aggregator->aggregator_identifier);
18251da177e4SLinus Torvalds }
18261da177e4SLinus Torvalds }
18271da177e4SLinus Torvalds
18281da177e4SLinus Torvalds /**
18291da177e4SLinus Torvalds * ad_initialize_agg - initialize a given aggregator's parameters
18301da177e4SLinus Torvalds * @aggregator: the aggregator we're looking at
18311da177e4SLinus Torvalds */
ad_initialize_agg(struct aggregator * aggregator)18321da177e4SLinus Torvalds static void ad_initialize_agg(struct aggregator *aggregator)
18331da177e4SLinus Torvalds {
18341da177e4SLinus Torvalds if (aggregator) {
18351da177e4SLinus Torvalds ad_clear_agg(aggregator);
18361da177e4SLinus Torvalds
1837f87fda00SEric Dumazet eth_zero_addr(aggregator->aggregator_mac_address.mac_addr_value);
18381da177e4SLinus Torvalds aggregator->aggregator_identifier = 0;
18391da177e4SLinus Torvalds aggregator->slave = NULL;
18401da177e4SLinus Torvalds }
18411da177e4SLinus Torvalds }
18421da177e4SLinus Torvalds
18431da177e4SLinus Torvalds /**
18441da177e4SLinus Torvalds * ad_initialize_port - initialize a given port's parameters
1845a35e5478SLee Jones * @port: the port we're looking at
18461da177e4SLinus Torvalds * @lacp_fast: boolean. whether fast periodic should be used
18471da177e4SLinus Torvalds */
ad_initialize_port(struct port * port,int lacp_fast)18481da177e4SLinus Torvalds static void ad_initialize_port(struct port *port, int lacp_fast)
18491da177e4SLinus Torvalds {
1850c7e703d0SHolger Eitzenberger static const struct port_params tmpl = {
1851c7e703d0SHolger Eitzenberger .system_priority = 0xffff,
1852c7e703d0SHolger Eitzenberger .key = 1,
1853c7e703d0SHolger Eitzenberger .port_number = 1,
1854c7e703d0SHolger Eitzenberger .port_priority = 0xff,
1855c7e703d0SHolger Eitzenberger .port_state = 1,
1856c7e703d0SHolger Eitzenberger };
18577addeef6SHolger Eitzenberger static const struct lacpdu lacpdu = {
18587addeef6SHolger Eitzenberger .subtype = 0x01,
18597addeef6SHolger Eitzenberger .version_number = 0x01,
18607addeef6SHolger Eitzenberger .tlv_type_actor_info = 0x01,
18617addeef6SHolger Eitzenberger .actor_information_length = 0x14,
18627addeef6SHolger Eitzenberger .tlv_type_partner_info = 0x02,
18637addeef6SHolger Eitzenberger .partner_information_length = 0x14,
18647addeef6SHolger Eitzenberger .tlv_type_collector_info = 0x03,
18657addeef6SHolger Eitzenberger .collector_information_length = 0x10,
18667addeef6SHolger Eitzenberger .collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY),
18677addeef6SHolger Eitzenberger };
1868c7e703d0SHolger Eitzenberger
18691da177e4SLinus Torvalds if (port) {
18701da177e4SLinus Torvalds port->actor_port_priority = 0xff;
18711da177e4SLinus Torvalds port->actor_port_aggregator_identifier = 0;
1872d238d458SHolger Eitzenberger port->ntt = false;
1873c1e46990SAndy Roulin port->actor_admin_port_state = LACP_STATE_AGGREGATION |
1874c1e46990SAndy Roulin LACP_STATE_LACP_ACTIVITY;
1875c1e46990SAndy Roulin port->actor_oper_port_state = LACP_STATE_AGGREGATION |
1876c1e46990SAndy Roulin LACP_STATE_LACP_ACTIVITY;
18771da177e4SLinus Torvalds
18787bfc4753SBandan Das if (lacp_fast)
1879c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_LACP_TIMEOUT;
18801da177e4SLinus Torvalds
1881c7e703d0SHolger Eitzenberger memcpy(&port->partner_admin, &tmpl, sizeof(tmpl));
1882c7e703d0SHolger Eitzenberger memcpy(&port->partner_oper, &tmpl, sizeof(tmpl));
1883c7e703d0SHolger Eitzenberger
1884f48127b6SHolger Eitzenberger port->is_enabled = true;
18853bf2d28aSVeaceslav Falico /* private parameters */
188619a12049SMahesh Bandewar port->sm_vars = AD_PORT_BEGIN | AD_PORT_LACP_ENABLED;
18871da177e4SLinus Torvalds port->sm_rx_state = 0;
18881da177e4SLinus Torvalds port->sm_rx_timer_counter = 0;
18891da177e4SLinus Torvalds port->sm_periodic_state = 0;
18901da177e4SLinus Torvalds port->sm_periodic_timer_counter = 0;
18911da177e4SLinus Torvalds port->sm_mux_state = 0;
18921da177e4SLinus Torvalds port->sm_mux_timer_counter = 0;
18931da177e4SLinus Torvalds port->sm_tx_state = 0;
18941da177e4SLinus Torvalds port->aggregator = NULL;
18951da177e4SLinus Torvalds port->next_port_in_aggregator = NULL;
18961da177e4SLinus Torvalds port->transaction_id = 0;
18971da177e4SLinus Torvalds
189814c9551aSMahesh Bandewar port->sm_churn_actor_timer_counter = 0;
189914c9551aSMahesh Bandewar port->sm_churn_actor_state = 0;
190014c9551aSMahesh Bandewar port->churn_actor_count = 0;
190114c9551aSMahesh Bandewar port->sm_churn_partner_timer_counter = 0;
190214c9551aSMahesh Bandewar port->sm_churn_partner_state = 0;
190314c9551aSMahesh Bandewar port->churn_partner_count = 0;
190414c9551aSMahesh Bandewar
19057addeef6SHolger Eitzenberger memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu));
19061da177e4SLinus Torvalds }
19071da177e4SLinus Torvalds }
19081da177e4SLinus Torvalds
19091da177e4SLinus Torvalds /**
19101da177e4SLinus Torvalds * ad_enable_collecting_distributing - enable a port's transmit/receive
19111da177e4SLinus Torvalds * @port: the port we're looking at
1912ee637714SMahesh Bandewar * @update_slave_arr: Does slave array need update?
19131da177e4SLinus Torvalds *
19141da177e4SLinus Torvalds * Enable @port if it's in an active aggregator
19151da177e4SLinus Torvalds */
ad_enable_collecting_distributing(struct port * port,bool * update_slave_arr)1916ee637714SMahesh Bandewar static void ad_enable_collecting_distributing(struct port *port,
1917ee637714SMahesh Bandewar bool *update_slave_arr)
19181da177e4SLinus Torvalds {
19191da177e4SLinus Torvalds if (port->aggregator->is_active) {
192017720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
192117720981SJarod Wilson "Enabling port %d (LAG %d)\n",
1922a4aee5c8SJoe Perches port->actor_port_number,
1923a4aee5c8SJoe Perches port->aggregator->aggregator_identifier);
19241da177e4SLinus Torvalds __enable_port(port);
1925ee637714SMahesh Bandewar /* Slave array needs update */
1926ee637714SMahesh Bandewar *update_slave_arr = true;
19271da177e4SLinus Torvalds }
19281da177e4SLinus Torvalds }
19291da177e4SLinus Torvalds
19301da177e4SLinus Torvalds /**
19311da177e4SLinus Torvalds * ad_disable_collecting_distributing - disable a port's transmit/receive
19321da177e4SLinus Torvalds * @port: the port we're looking at
1933ee637714SMahesh Bandewar * @update_slave_arr: Does slave array need update?
19341da177e4SLinus Torvalds */
ad_disable_collecting_distributing(struct port * port,bool * update_slave_arr)1935ee637714SMahesh Bandewar static void ad_disable_collecting_distributing(struct port *port,
1936ee637714SMahesh Bandewar bool *update_slave_arr)
19371da177e4SLinus Torvalds {
19383bf2d28aSVeaceslav Falico if (port->aggregator &&
19393bf2d28aSVeaceslav Falico !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system),
19403bf2d28aSVeaceslav Falico &(null_mac_addr))) {
194117720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
194217720981SJarod Wilson "Disabling port %d (LAG %d)\n",
1943a4aee5c8SJoe Perches port->actor_port_number,
1944a4aee5c8SJoe Perches port->aggregator->aggregator_identifier);
19451da177e4SLinus Torvalds __disable_port(port);
1946ee637714SMahesh Bandewar /* Slave array needs an update */
1947ee637714SMahesh Bandewar *update_slave_arr = true;
19481da177e4SLinus Torvalds }
19491da177e4SLinus Torvalds }
19501da177e4SLinus Torvalds
19511da177e4SLinus Torvalds /**
19521da177e4SLinus Torvalds * ad_marker_info_received - handle receive of a Marker information frame
19531da177e4SLinus Torvalds * @marker_info: Marker info received
19541da177e4SLinus Torvalds * @port: the port we're looking at
19551da177e4SLinus Torvalds */
ad_marker_info_received(struct bond_marker * marker_info,struct port * port)19561c3f0b8eSMathieu Desnoyers static void ad_marker_info_received(struct bond_marker *marker_info,
19571c3f0b8eSMathieu Desnoyers struct port *port)
19581da177e4SLinus Torvalds {
19591c3f0b8eSMathieu Desnoyers struct bond_marker marker;
19601da177e4SLinus Torvalds
1961267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.marker_rx);
1962949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(port->slave->bond).stats.marker_rx);
1963267c095aSNikolay Aleksandrov
19643bf2d28aSVeaceslav Falico /* copy the received marker data to the response marker */
19651c3f0b8eSMathieu Desnoyers memcpy(&marker, marker_info, sizeof(struct bond_marker));
19663bf2d28aSVeaceslav Falico /* change the marker subtype to marker response */
19671da177e4SLinus Torvalds marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE;
19681da177e4SLinus Torvalds
19693bf2d28aSVeaceslav Falico /* send the marker response */
197017720981SJarod Wilson if (ad_marker_send(port, &marker) >= 0)
197117720981SJarod Wilson slave_dbg(port->slave->bond->dev, port->slave->dev,
197217720981SJarod Wilson "Sent Marker Response on port %d\n",
1973a4aee5c8SJoe Perches port->actor_port_number);
19741da177e4SLinus Torvalds }
19751da177e4SLinus Torvalds
19761da177e4SLinus Torvalds /**
19771da177e4SLinus Torvalds * ad_marker_response_received - handle receive of a marker response frame
19781da177e4SLinus Torvalds * @marker: marker PDU received
19791da177e4SLinus Torvalds * @port: the port we're looking at
19801da177e4SLinus Torvalds *
19811da177e4SLinus Torvalds * This function does nothing since we decided not to implement send and handle
19821da177e4SLinus Torvalds * response for marker PDU's, in this stage, but only to respond to marker
19831da177e4SLinus Torvalds * information.
19841da177e4SLinus Torvalds */
ad_marker_response_received(struct bond_marker * marker,struct port * port)19851c3f0b8eSMathieu Desnoyers static void ad_marker_response_received(struct bond_marker *marker,
19861c3f0b8eSMathieu Desnoyers struct port *port)
19871da177e4SLinus Torvalds {
1988267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(port->slave)->stats.marker_resp_rx);
1989949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(port->slave->bond).stats.marker_resp_rx);
1990267c095aSNikolay Aleksandrov
19913bf2d28aSVeaceslav Falico /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */
19921da177e4SLinus Torvalds }
19931da177e4SLinus Torvalds
19943bf2d28aSVeaceslav Falico /* ========= AD exported functions to the main bonding code ========= */
19951da177e4SLinus Torvalds
19963bf2d28aSVeaceslav Falico /* Check aggregators status in team every T seconds */
19971da177e4SLinus Torvalds #define AD_AGGREGATOR_SELECTION_TIMER 8
19981da177e4SLinus Torvalds
19993bf2d28aSVeaceslav Falico /**
20003bf2d28aSVeaceslav Falico * bond_3ad_initiate_agg_selection - initate aggregator selection
20013bf2d28aSVeaceslav Falico * @bond: bonding struct
2002a35e5478SLee Jones * @timeout: timeout value to set
2003fd989c83SJay Vosburgh *
2004fd989c83SJay Vosburgh * Set the aggregation selection timer, to initiate an agg selection in
2005fd989c83SJay Vosburgh * the very near future. Called during first initialization, and during
2006fd989c83SJay Vosburgh * any down to up transitions of the bond.
2007fd989c83SJay Vosburgh */
bond_3ad_initiate_agg_selection(struct bonding * bond,int timeout)2008fd989c83SJay Vosburgh void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
2009fd989c83SJay Vosburgh {
20109ceaf6f7SEric Dumazet atomic_set(&BOND_AD_INFO(bond).agg_select_timer, timeout);
2011fd989c83SJay Vosburgh }
2012fd989c83SJay Vosburgh
20131da177e4SLinus Torvalds /**
20141da177e4SLinus Torvalds * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
20151da177e4SLinus Torvalds * @bond: bonding struct to work on
20161da177e4SLinus Torvalds *
20171da177e4SLinus Torvalds * Can be called only after the mac address of the bond is set.
20181da177e4SLinus Torvalds */
bond_3ad_initialize(struct bonding * bond)2019f2e44dffSJonathan Toppins void bond_3ad_initialize(struct bonding *bond)
20201da177e4SLinus Torvalds {
2021163c8ff3SJiri Bohac BOND_AD_INFO(bond).aggregator_identifier = 0;
20226791e466SMahesh Bandewar BOND_AD_INFO(bond).system.sys_priority =
20236791e466SMahesh Bandewar bond->params.ad_actor_sys_prio;
202474514957SMahesh Bandewar if (is_zero_ether_addr(bond->params.ad_actor_system))
202574514957SMahesh Bandewar BOND_AD_INFO(bond).system.sys_mac_addr =
202674514957SMahesh Bandewar *((struct mac_addr *)bond->dev->dev_addr);
202774514957SMahesh Bandewar else
202874514957SMahesh Bandewar BOND_AD_INFO(bond).system.sys_mac_addr =
202974514957SMahesh Bandewar *((struct mac_addr *)bond->params.ad_actor_system);
20301da177e4SLinus Torvalds
2031fd989c83SJay Vosburgh bond_3ad_initiate_agg_selection(bond,
2032fd989c83SJay Vosburgh AD_AGGREGATOR_SELECTION_TIMER *
2033fd989c83SJay Vosburgh ad_ticks_per_sec);
20341da177e4SLinus Torvalds }
20351da177e4SLinus Torvalds
20361da177e4SLinus Torvalds /**
20371da177e4SLinus Torvalds * bond_3ad_bind_slave - initialize a slave's port
20381da177e4SLinus Torvalds * @slave: slave struct to work on
20391da177e4SLinus Torvalds *
20401da177e4SLinus Torvalds * Returns: 0 on success
20411da177e4SLinus Torvalds * < 0 on error
20421da177e4SLinus Torvalds */
bond_3ad_bind_slave(struct slave * slave)2043359632e5Sdingtianhong void bond_3ad_bind_slave(struct slave *slave)
20441da177e4SLinus Torvalds {
20451da177e4SLinus Torvalds struct bonding *bond = bond_get_bond_by_slave(slave);
20461da177e4SLinus Torvalds struct port *port;
20471da177e4SLinus Torvalds struct aggregator *aggregator;
20481da177e4SLinus Torvalds
2049359632e5Sdingtianhong /* check that the slave has not been initialized yet. */
20503fdddd85Sdingtianhong if (SLAVE_AD_INFO(slave)->port.slave != slave) {
20511da177e4SLinus Torvalds
2052359632e5Sdingtianhong /* port initialization */
20533fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
20541da177e4SLinus Torvalds
2055bf0239a9SPeter Pan(潘卫平) ad_initialize_port(port, bond->params.lacp_fast);
20561da177e4SLinus Torvalds
20571da177e4SLinus Torvalds port->slave = slave;
20583fdddd85Sdingtianhong port->actor_port_number = SLAVE_AD_INFO(slave)->id;
2059d22a5fc0SMahesh Bandewar /* key is determined according to the link speed, duplex and
2060d22a5fc0SMahesh Bandewar * user key
2061359632e5Sdingtianhong */
2062d22a5fc0SMahesh Bandewar port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
20637bb11dc9SMahesh Bandewar ad_update_actor_keys(port, false);
2064359632e5Sdingtianhong /* actor system is the bond's system */
20655ee14e6dSNikolay Aleksandrov __ad_actor_update_port(port);
20663bf2d28aSVeaceslav Falico /* tx timer(to verify that no more than MAX_TX_IN_SECOND
20673bf2d28aSVeaceslav Falico * lacpdu's are sent in one second)
20683bf2d28aSVeaceslav Falico */
20691da177e4SLinus Torvalds port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
20701da177e4SLinus Torvalds
20711da177e4SLinus Torvalds __disable_port(port);
20721da177e4SLinus Torvalds
2073359632e5Sdingtianhong /* aggregator initialization */
20743fdddd85Sdingtianhong aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
20751da177e4SLinus Torvalds
20761da177e4SLinus Torvalds ad_initialize_agg(aggregator);
20771da177e4SLinus Torvalds
20781da177e4SLinus Torvalds aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
2079163c8ff3SJiri Bohac aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
20801da177e4SLinus Torvalds aggregator->slave = slave;
20811da177e4SLinus Torvalds aggregator->is_active = 0;
20821da177e4SLinus Torvalds aggregator->num_of_ports = 0;
20831da177e4SLinus Torvalds }
20841da177e4SLinus Torvalds }
20851da177e4SLinus Torvalds
20861da177e4SLinus Torvalds /**
20871da177e4SLinus Torvalds * bond_3ad_unbind_slave - deinitialize a slave's port
20881da177e4SLinus Torvalds * @slave: slave struct to work on
20891da177e4SLinus Torvalds *
20901da177e4SLinus Torvalds * Search for the aggregator that is related to this port, remove the
20911da177e4SLinus Torvalds * aggregator and assign another aggregator for other port related to it
20921da177e4SLinus Torvalds * (if any), and remove the port.
20931da177e4SLinus Torvalds */
bond_3ad_unbind_slave(struct slave * slave)20941da177e4SLinus Torvalds void bond_3ad_unbind_slave(struct slave *slave)
20951da177e4SLinus Torvalds {
20961da177e4SLinus Torvalds struct port *port, *prev_port, *temp_port;
20971da177e4SLinus Torvalds struct aggregator *aggregator, *new_aggregator, *temp_aggregator;
20981da177e4SLinus Torvalds int select_new_active_agg = 0;
20990b088264SVeaceslav Falico struct bonding *bond = slave->bond;
21000b088264SVeaceslav Falico struct slave *slave_iter;
21010b088264SVeaceslav Falico struct list_head *iter;
2102ee637714SMahesh Bandewar bool dummy_slave_update; /* Ignore this value as caller updates array */
21031da177e4SLinus Torvalds
2104e470259fSNikolay Aleksandrov /* Sync against bond_3ad_state_machine_handler() */
2105e470259fSNikolay Aleksandrov spin_lock_bh(&bond->mode_lock);
21063fdddd85Sdingtianhong aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
21073fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
21081da177e4SLinus Torvalds
21093bf2d28aSVeaceslav Falico /* if slave is null, the whole port is not initialized */
21101da177e4SLinus Torvalds if (!port->slave) {
211117720981SJarod Wilson slave_warn(bond->dev, slave->dev, "Trying to unbind an uninitialized port\n");
2112e470259fSNikolay Aleksandrov goto out;
21131da177e4SLinus Torvalds }
21141da177e4SLinus Torvalds
211517720981SJarod Wilson slave_dbg(bond->dev, slave->dev, "Unbinding Link Aggregation Group %d\n",
2116a4aee5c8SJoe Perches aggregator->aggregator_identifier);
21171da177e4SLinus Torvalds
21181da177e4SLinus Torvalds /* Tell the partner that this port is not suitable for aggregation */
2119c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
2120c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_COLLECTING;
2121c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
2122c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_AGGREGATION;
21231da177e4SLinus Torvalds __update_lacpdu_from_port(port);
21241da177e4SLinus Torvalds ad_lacpdu_send(port);
21251da177e4SLinus Torvalds
21263bf2d28aSVeaceslav Falico /* check if this aggregator is occupied */
21271da177e4SLinus Torvalds if (aggregator->lag_ports) {
21283bf2d28aSVeaceslav Falico /* check if there are other ports related to this aggregator
21293bf2d28aSVeaceslav Falico * except the port related to this slave(thats ensure us that
21303bf2d28aSVeaceslav Falico * there is a reason to search for new aggregator, and that we
21313bf2d28aSVeaceslav Falico * will find one
21323bf2d28aSVeaceslav Falico */
21333bf2d28aSVeaceslav Falico if ((aggregator->lag_ports != port) ||
21343bf2d28aSVeaceslav Falico (aggregator->lag_ports->next_port_in_aggregator)) {
21353bf2d28aSVeaceslav Falico /* find new aggregator for the related port(s) */
21360b088264SVeaceslav Falico bond_for_each_slave(bond, slave_iter, iter) {
21373fdddd85Sdingtianhong new_aggregator = &(SLAVE_AD_INFO(slave_iter)->aggregator);
21383bf2d28aSVeaceslav Falico /* if the new aggregator is empty, or it is
21393bf2d28aSVeaceslav Falico * connected to our port only
21403bf2d28aSVeaceslav Falico */
21413bf2d28aSVeaceslav Falico if (!new_aggregator->lag_ports ||
21423bf2d28aSVeaceslav Falico ((new_aggregator->lag_ports == port) &&
21433bf2d28aSVeaceslav Falico !new_aggregator->lag_ports->next_port_in_aggregator))
21441da177e4SLinus Torvalds break;
21451da177e4SLinus Torvalds }
21460b088264SVeaceslav Falico if (!slave_iter)
21470b088264SVeaceslav Falico new_aggregator = NULL;
21483bf2d28aSVeaceslav Falico
21493bf2d28aSVeaceslav Falico /* if new aggregator found, copy the aggregator's
21503bf2d28aSVeaceslav Falico * parameters and connect the related lag_ports to the
21513bf2d28aSVeaceslav Falico * new aggregator
21523bf2d28aSVeaceslav Falico */
21531da177e4SLinus Torvalds if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
215417720981SJarod Wilson slave_dbg(bond->dev, slave->dev, "Some port(s) related to LAG %d - replacing with LAG %d\n",
2155a4aee5c8SJoe Perches aggregator->aggregator_identifier,
2156a4aee5c8SJoe Perches new_aggregator->aggregator_identifier);
21571da177e4SLinus Torvalds
21583bf2d28aSVeaceslav Falico if ((new_aggregator->lag_ports == port) &&
21593bf2d28aSVeaceslav Falico new_aggregator->is_active) {
216017720981SJarod Wilson slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
21611da177e4SLinus Torvalds select_new_active_agg = 1;
21621da177e4SLinus Torvalds }
21631da177e4SLinus Torvalds
21641da177e4SLinus Torvalds new_aggregator->is_individual = aggregator->is_individual;
21651da177e4SLinus Torvalds new_aggregator->actor_admin_aggregator_key = aggregator->actor_admin_aggregator_key;
21661da177e4SLinus Torvalds new_aggregator->actor_oper_aggregator_key = aggregator->actor_oper_aggregator_key;
21671da177e4SLinus Torvalds new_aggregator->partner_system = aggregator->partner_system;
21681da177e4SLinus Torvalds new_aggregator->partner_system_priority = aggregator->partner_system_priority;
21691da177e4SLinus Torvalds new_aggregator->partner_oper_aggregator_key = aggregator->partner_oper_aggregator_key;
21701da177e4SLinus Torvalds new_aggregator->receive_state = aggregator->receive_state;
21711da177e4SLinus Torvalds new_aggregator->transmit_state = aggregator->transmit_state;
21721da177e4SLinus Torvalds new_aggregator->lag_ports = aggregator->lag_ports;
21731da177e4SLinus Torvalds new_aggregator->is_active = aggregator->is_active;
21741da177e4SLinus Torvalds new_aggregator->num_of_ports = aggregator->num_of_ports;
21751da177e4SLinus Torvalds
21763bf2d28aSVeaceslav Falico /* update the information that is written on
21773bf2d28aSVeaceslav Falico * the ports about the aggregator
21783bf2d28aSVeaceslav Falico */
2179128ea6c3SBandan Das for (temp_port = aggregator->lag_ports; temp_port;
2180128ea6c3SBandan Das temp_port = temp_port->next_port_in_aggregator) {
21811da177e4SLinus Torvalds temp_port->aggregator = new_aggregator;
21821da177e4SLinus Torvalds temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
21831da177e4SLinus Torvalds }
21841da177e4SLinus Torvalds
21851da177e4SLinus Torvalds ad_clear_agg(aggregator);
21861da177e4SLinus Torvalds
21877bfc4753SBandan Das if (select_new_active_agg)
2188ee637714SMahesh Bandewar ad_agg_selection_logic(__get_first_agg(port),
2189ee637714SMahesh Bandewar &dummy_slave_update);
21901da177e4SLinus Torvalds } else {
219117720981SJarod Wilson slave_warn(bond->dev, slave->dev, "unbinding aggregator, and could not find a new aggregator for its ports\n");
21921da177e4SLinus Torvalds }
21933bf2d28aSVeaceslav Falico } else {
21943bf2d28aSVeaceslav Falico /* in case that the only port related to this
21953bf2d28aSVeaceslav Falico * aggregator is the one we want to remove
21963bf2d28aSVeaceslav Falico */
21971da177e4SLinus Torvalds select_new_active_agg = aggregator->is_active;
21981da177e4SLinus Torvalds ad_clear_agg(aggregator);
21991da177e4SLinus Torvalds if (select_new_active_agg) {
220017720981SJarod Wilson slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
22013bf2d28aSVeaceslav Falico /* select new active aggregator */
220274684493SVeaceslav Falico temp_aggregator = __get_first_agg(port);
220374684493SVeaceslav Falico if (temp_aggregator)
2204ee637714SMahesh Bandewar ad_agg_selection_logic(temp_aggregator,
2205ee637714SMahesh Bandewar &dummy_slave_update);
22061da177e4SLinus Torvalds }
22071da177e4SLinus Torvalds }
22081da177e4SLinus Torvalds }
22091da177e4SLinus Torvalds
221017720981SJarod Wilson slave_dbg(bond->dev, slave->dev, "Unbinding port %d\n", port->actor_port_number);
22113bf2d28aSVeaceslav Falico
22123bf2d28aSVeaceslav Falico /* find the aggregator that this port is connected to */
22130b088264SVeaceslav Falico bond_for_each_slave(bond, slave_iter, iter) {
22143fdddd85Sdingtianhong temp_aggregator = &(SLAVE_AD_INFO(slave_iter)->aggregator);
22151da177e4SLinus Torvalds prev_port = NULL;
22163bf2d28aSVeaceslav Falico /* search the port in the aggregator's related ports */
2217128ea6c3SBandan Das for (temp_port = temp_aggregator->lag_ports; temp_port;
2218128ea6c3SBandan Das prev_port = temp_port,
2219128ea6c3SBandan Das temp_port = temp_port->next_port_in_aggregator) {
22203bf2d28aSVeaceslav Falico if (temp_port == port) {
22213bf2d28aSVeaceslav Falico /* the aggregator found - detach the port from
22223bf2d28aSVeaceslav Falico * this aggregator
22233bf2d28aSVeaceslav Falico */
22247bfc4753SBandan Das if (prev_port)
22251da177e4SLinus Torvalds prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator;
22267bfc4753SBandan Das else
22271da177e4SLinus Torvalds temp_aggregator->lag_ports = temp_port->next_port_in_aggregator;
22281da177e4SLinus Torvalds temp_aggregator->num_of_ports--;
22290622cab0SJay Vosburgh if (__agg_active_ports(temp_aggregator) == 0) {
22301da177e4SLinus Torvalds select_new_active_agg = temp_aggregator->is_active;
2231050133e1SYevhen Orlov if (temp_aggregator->num_of_ports == 0)
22321da177e4SLinus Torvalds ad_clear_agg(temp_aggregator);
22331da177e4SLinus Torvalds if (select_new_active_agg) {
223417720981SJarod Wilson slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
22353bf2d28aSVeaceslav Falico /* select new active aggregator */
2236ee637714SMahesh Bandewar ad_agg_selection_logic(__get_first_agg(port),
2237ee637714SMahesh Bandewar &dummy_slave_update);
22381da177e4SLinus Torvalds }
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds break;
22411da177e4SLinus Torvalds }
22421da177e4SLinus Torvalds }
22431da177e4SLinus Torvalds }
22441da177e4SLinus Torvalds port->slave = NULL;
2245e470259fSNikolay Aleksandrov
2246e470259fSNikolay Aleksandrov out:
2247e470259fSNikolay Aleksandrov spin_unlock_bh(&bond->mode_lock);
22481da177e4SLinus Torvalds }
22491da177e4SLinus Torvalds
22501da177e4SLinus Torvalds /**
22515ee14e6dSNikolay Aleksandrov * bond_3ad_update_ad_actor_settings - reflect change of actor settings to ports
22525ee14e6dSNikolay Aleksandrov * @bond: bonding struct to work on
22535ee14e6dSNikolay Aleksandrov *
22545ee14e6dSNikolay Aleksandrov * If an ad_actor setting gets changed we need to update the individual port
22555ee14e6dSNikolay Aleksandrov * settings so the bond device will use the new values when it gets upped.
22565ee14e6dSNikolay Aleksandrov */
bond_3ad_update_ad_actor_settings(struct bonding * bond)22575ee14e6dSNikolay Aleksandrov void bond_3ad_update_ad_actor_settings(struct bonding *bond)
22585ee14e6dSNikolay Aleksandrov {
22595ee14e6dSNikolay Aleksandrov struct list_head *iter;
22605ee14e6dSNikolay Aleksandrov struct slave *slave;
22615ee14e6dSNikolay Aleksandrov
22625ee14e6dSNikolay Aleksandrov ASSERT_RTNL();
22635ee14e6dSNikolay Aleksandrov
22645ee14e6dSNikolay Aleksandrov BOND_AD_INFO(bond).system.sys_priority = bond->params.ad_actor_sys_prio;
22655ee14e6dSNikolay Aleksandrov if (is_zero_ether_addr(bond->params.ad_actor_system))
22665ee14e6dSNikolay Aleksandrov BOND_AD_INFO(bond).system.sys_mac_addr =
22675ee14e6dSNikolay Aleksandrov *((struct mac_addr *)bond->dev->dev_addr);
22685ee14e6dSNikolay Aleksandrov else
22695ee14e6dSNikolay Aleksandrov BOND_AD_INFO(bond).system.sys_mac_addr =
22705ee14e6dSNikolay Aleksandrov *((struct mac_addr *)bond->params.ad_actor_system);
22715ee14e6dSNikolay Aleksandrov
22725ee14e6dSNikolay Aleksandrov spin_lock_bh(&bond->mode_lock);
22737f20cd25SNikolay Aleksandrov bond_for_each_slave(bond, slave, iter) {
22747f20cd25SNikolay Aleksandrov struct port *port = &(SLAVE_AD_INFO(slave))->port;
22757f20cd25SNikolay Aleksandrov
22767f20cd25SNikolay Aleksandrov __ad_actor_update_port(port);
22777f20cd25SNikolay Aleksandrov port->ntt = true;
22787f20cd25SNikolay Aleksandrov }
22795ee14e6dSNikolay Aleksandrov spin_unlock_bh(&bond->mode_lock);
22805ee14e6dSNikolay Aleksandrov }
22815ee14e6dSNikolay Aleksandrov
22825ee14e6dSNikolay Aleksandrov /**
22839ceaf6f7SEric Dumazet * bond_agg_timer_advance - advance agg_select_timer
22849ceaf6f7SEric Dumazet * @bond: bonding structure
22859ceaf6f7SEric Dumazet *
22869ceaf6f7SEric Dumazet * Return true when agg_select_timer reaches 0.
22879ceaf6f7SEric Dumazet */
bond_agg_timer_advance(struct bonding * bond)22889ceaf6f7SEric Dumazet static bool bond_agg_timer_advance(struct bonding *bond)
22899ceaf6f7SEric Dumazet {
22909ceaf6f7SEric Dumazet int val, nval;
22919ceaf6f7SEric Dumazet
22929ceaf6f7SEric Dumazet while (1) {
22939ceaf6f7SEric Dumazet val = atomic_read(&BOND_AD_INFO(bond).agg_select_timer);
22949ceaf6f7SEric Dumazet if (!val)
22959ceaf6f7SEric Dumazet return false;
22969ceaf6f7SEric Dumazet nval = val - 1;
22979ceaf6f7SEric Dumazet if (atomic_cmpxchg(&BOND_AD_INFO(bond).agg_select_timer,
22989ceaf6f7SEric Dumazet val, nval) == val)
22999ceaf6f7SEric Dumazet break;
23009ceaf6f7SEric Dumazet }
23019ceaf6f7SEric Dumazet return nval == 0;
23029ceaf6f7SEric Dumazet }
23039ceaf6f7SEric Dumazet
23049ceaf6f7SEric Dumazet /**
23051da177e4SLinus Torvalds * bond_3ad_state_machine_handler - handle state machines timeout
2306a35e5478SLee Jones * @work: work context to fetch bonding struct to work on from
23071da177e4SLinus Torvalds *
23081da177e4SLinus Torvalds * The state machine handling concept in this module is to check every tick
23091da177e4SLinus Torvalds * which state machine should operate any function. The execution order is
23101da177e4SLinus Torvalds * round robin, so when we have an interaction between state machines, the
23111da177e4SLinus Torvalds * reply of one to each other might be delayed until next tick.
23121da177e4SLinus Torvalds *
23131da177e4SLinus Torvalds * This function also complete the initialization when the agg_select_timer
23141da177e4SLinus Torvalds * times out, and it selects an aggregator for the ports that are yet not
23151da177e4SLinus Torvalds * related to any aggregator, and selects the active aggregator for a bond.
23161da177e4SLinus Torvalds */
bond_3ad_state_machine_handler(struct work_struct * work)23171b76b316SJay Vosburgh void bond_3ad_state_machine_handler(struct work_struct *work)
23181da177e4SLinus Torvalds {
23191b76b316SJay Vosburgh struct bonding *bond = container_of(work, struct bonding,
23201b76b316SJay Vosburgh ad_work.work);
23211da177e4SLinus Torvalds struct aggregator *aggregator;
23223c4c88a1SVeaceslav Falico struct list_head *iter;
23233c4c88a1SVeaceslav Falico struct slave *slave;
23243c4c88a1SVeaceslav Falico struct port *port;
23255e5b0665Sdingtianhong bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
2326ee637714SMahesh Bandewar bool update_slave_arr = false;
23271da177e4SLinus Torvalds
2328e470259fSNikolay Aleksandrov /* Lock to protect data accessed by all (e.g., port->sm_vars) and
2329e470259fSNikolay Aleksandrov * against running with bond_3ad_unbind_slave. ad_rx_machine may run
2330e470259fSNikolay Aleksandrov * concurrently due to incoming LACPDU as well.
2331e470259fSNikolay Aleksandrov */
2332b7435628SNikolay Aleksandrov spin_lock_bh(&bond->mode_lock);
2333be79bd04Sdingtianhong rcu_read_lock();
23341f2cd845SDavid S. Miller
2335be79bd04Sdingtianhong /* check if there are any slaves */
23360965a1f3SVeaceslav Falico if (!bond_has_slaves(bond))
23371da177e4SLinus Torvalds goto re_arm;
23381da177e4SLinus Torvalds
23399ceaf6f7SEric Dumazet if (bond_agg_timer_advance(bond)) {
2340be79bd04Sdingtianhong slave = bond_first_slave_rcu(bond);
23413fdddd85Sdingtianhong port = slave ? &(SLAVE_AD_INFO(slave)->port) : NULL;
2342fe9323daSVeaceslav Falico
2343be79bd04Sdingtianhong /* select the active aggregator for the bond */
2344fe9323daSVeaceslav Falico if (port) {
23451da177e4SLinus Torvalds if (!port->slave) {
2346d4471f5eSVeaceslav Falico net_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n",
2347a4aee5c8SJoe Perches bond->dev->name);
23481da177e4SLinus Torvalds goto re_arm;
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds
23511da177e4SLinus Torvalds aggregator = __get_first_agg(port);
2352ee637714SMahesh Bandewar ad_agg_selection_logic(aggregator, &update_slave_arr);
23531da177e4SLinus Torvalds }
2354f0c76d61SJay Vosburgh bond_3ad_set_carrier(bond);
23551da177e4SLinus Torvalds }
23561da177e4SLinus Torvalds
2357be79bd04Sdingtianhong /* for each port run the state machines */
2358be79bd04Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter) {
23593fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
23601da177e4SLinus Torvalds if (!port->slave) {
2361d4471f5eSVeaceslav Falico net_warn_ratelimited("%s: Warning: Found an uninitialized port\n",
2362a4aee5c8SJoe Perches bond->dev->name);
23631da177e4SLinus Torvalds goto re_arm;
23641da177e4SLinus Torvalds }
23651da177e4SLinus Torvalds
23661da177e4SLinus Torvalds ad_rx_machine(NULL, port);
2367bbef56d8SColin Ian King ad_periodic_machine(port, &bond->params);
2368ee637714SMahesh Bandewar ad_port_selection_logic(port, &update_slave_arr);
2369ee637714SMahesh Bandewar ad_mux_machine(port, &update_slave_arr);
23701da177e4SLinus Torvalds ad_tx_machine(port);
237114c9551aSMahesh Bandewar ad_churn_machine(port);
23721da177e4SLinus Torvalds
2373be79bd04Sdingtianhong /* turn off the BEGIN bit, since we already handled it */
23747bfc4753SBandan Das if (port->sm_vars & AD_PORT_BEGIN)
23751da177e4SLinus Torvalds port->sm_vars &= ~AD_PORT_BEGIN;
23761da177e4SLinus Torvalds }
23771da177e4SLinus Torvalds
23781da177e4SLinus Torvalds re_arm:
23795e5b0665Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter) {
23805e5b0665Sdingtianhong if (slave->should_notify) {
23815e5b0665Sdingtianhong should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
23825e5b0665Sdingtianhong break;
23835e5b0665Sdingtianhong }
23845e5b0665Sdingtianhong }
2385be79bd04Sdingtianhong rcu_read_unlock();
2386b7435628SNikolay Aleksandrov spin_unlock_bh(&bond->mode_lock);
23875e5b0665Sdingtianhong
2388ee637714SMahesh Bandewar if (update_slave_arr)
2389ee637714SMahesh Bandewar bond_slave_arr_work_rearm(bond, 0);
2390ee637714SMahesh Bandewar
23915e5b0665Sdingtianhong if (should_notify_rtnl && rtnl_trylock()) {
2392b0929915Sdingtianhong bond_slave_state_notify(bond);
23935e5b0665Sdingtianhong rtnl_unlock();
23945e5b0665Sdingtianhong }
2395be79bd04Sdingtianhong queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
23961da177e4SLinus Torvalds }
23971da177e4SLinus Torvalds
23981da177e4SLinus Torvalds /**
23991da177e4SLinus Torvalds * bond_3ad_rx_indication - handle a received frame
24001da177e4SLinus Torvalds * @lacpdu: received lacpdu
24011da177e4SLinus Torvalds * @slave: slave struct to work on
24021da177e4SLinus Torvalds *
24031da177e4SLinus Torvalds * It is assumed that frames that were sent on this NIC don't returned as new
24041da177e4SLinus Torvalds * received frames (loopback). Since only the payload is given to this
24051da177e4SLinus Torvalds * function, it check for loopback.
24061da177e4SLinus Torvalds */
bond_3ad_rx_indication(struct lacpdu * lacpdu,struct slave * slave)2407dadeb61dSNikolay Aleksandrov static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave)
24081da177e4SLinus Torvalds {
2409949e7ceaSNikolay Aleksandrov struct bonding *bond = slave->bond;
241013a8e0c8SJiri Bohac int ret = RX_HANDLER_ANOTHER;
24113d021715SNikolay Aleksandrov struct bond_marker *marker;
24123d021715SNikolay Aleksandrov struct port *port;
2413267c095aSNikolay Aleksandrov atomic64_t *stat;
24141da177e4SLinus Torvalds
24153fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
24161da177e4SLinus Torvalds if (!port->slave) {
2417d4471f5eSVeaceslav Falico net_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
2418471cb5a3SJiri Pirko slave->dev->name, slave->bond->dev->name);
241913a8e0c8SJiri Bohac return ret;
24201da177e4SLinus Torvalds }
24211da177e4SLinus Torvalds
24221da177e4SLinus Torvalds switch (lacpdu->subtype) {
24231da177e4SLinus Torvalds case AD_TYPE_LACPDU:
242413a8e0c8SJiri Bohac ret = RX_HANDLER_CONSUMED;
242517720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev,
242617720981SJarod Wilson "Received LACPDU on port %d\n",
242717720981SJarod Wilson port->actor_port_number);
242816d79d7dSNils Carlson /* Protect against concurrent state machines */
2429e470259fSNikolay Aleksandrov spin_lock(&slave->bond->mode_lock);
24301da177e4SLinus Torvalds ad_rx_machine(lacpdu, port);
2431e470259fSNikolay Aleksandrov spin_unlock(&slave->bond->mode_lock);
24321da177e4SLinus Torvalds break;
24331da177e4SLinus Torvalds case AD_TYPE_MARKER:
243413a8e0c8SJiri Bohac ret = RX_HANDLER_CONSUMED;
24353bf2d28aSVeaceslav Falico /* No need to convert fields to Little Endian since we
24363bf2d28aSVeaceslav Falico * don't use the marker's fields.
24373bf2d28aSVeaceslav Falico */
24383d021715SNikolay Aleksandrov marker = (struct bond_marker *)lacpdu;
24393d021715SNikolay Aleksandrov switch (marker->tlv_type) {
24401da177e4SLinus Torvalds case AD_MARKER_INFORMATION_SUBTYPE:
244117720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Received Marker Information on port %d\n",
2442a4aee5c8SJoe Perches port->actor_port_number);
24433d021715SNikolay Aleksandrov ad_marker_info_received(marker, port);
24441da177e4SLinus Torvalds break;
24451da177e4SLinus Torvalds case AD_MARKER_RESPONSE_SUBTYPE:
244617720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Received Marker Response on port %d\n",
2447a4aee5c8SJoe Perches port->actor_port_number);
24483d021715SNikolay Aleksandrov ad_marker_response_received(marker, port);
24491da177e4SLinus Torvalds break;
24501da177e4SLinus Torvalds default:
245117720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Received an unknown Marker subtype on port %d\n",
2452a4aee5c8SJoe Perches port->actor_port_number);
2453267c095aSNikolay Aleksandrov stat = &SLAVE_AD_INFO(slave)->stats.marker_unknown_rx;
2454267c095aSNikolay Aleksandrov atomic64_inc(stat);
2455949e7ceaSNikolay Aleksandrov stat = &BOND_AD_INFO(bond).stats.marker_unknown_rx;
2456949e7ceaSNikolay Aleksandrov atomic64_inc(stat);
24571da177e4SLinus Torvalds }
2458267c095aSNikolay Aleksandrov break;
2459267c095aSNikolay Aleksandrov default:
2460267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_unknown_rx);
2461949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(bond).stats.lacpdu_unknown_rx);
24621da177e4SLinus Torvalds }
24633d021715SNikolay Aleksandrov
246413a8e0c8SJiri Bohac return ret;
24651da177e4SLinus Torvalds }
24661da177e4SLinus Torvalds
24671da177e4SLinus Torvalds /**
24687bb11dc9SMahesh Bandewar * ad_update_actor_keys - Update the oper / admin keys for a port based on
24697bb11dc9SMahesh Bandewar * its current speed and duplex settings.
24707bb11dc9SMahesh Bandewar *
24717bb11dc9SMahesh Bandewar * @port: the port we'are looking at
24727bb11dc9SMahesh Bandewar * @reset: Boolean to just reset the speed and the duplex part of the key
24737bb11dc9SMahesh Bandewar *
24747bb11dc9SMahesh Bandewar * The logic to change the oper / admin keys is:
24757bb11dc9SMahesh Bandewar * (a) A full duplex port can participate in LACP with partner.
24767bb11dc9SMahesh Bandewar * (b) When the speed is changed, LACP need to be reinitiated.
24777bb11dc9SMahesh Bandewar */
ad_update_actor_keys(struct port * port,bool reset)24787bb11dc9SMahesh Bandewar static void ad_update_actor_keys(struct port *port, bool reset)
24797bb11dc9SMahesh Bandewar {
24807bb11dc9SMahesh Bandewar u8 duplex = 0;
24817bb11dc9SMahesh Bandewar u16 ospeed = 0, speed = 0;
24827bb11dc9SMahesh Bandewar u16 old_oper_key = port->actor_oper_port_key;
24837bb11dc9SMahesh Bandewar
24847bb11dc9SMahesh Bandewar port->actor_admin_port_key &= ~(AD_SPEED_KEY_MASKS|AD_DUPLEX_KEY_MASKS);
24857bb11dc9SMahesh Bandewar if (!reset) {
24867bb11dc9SMahesh Bandewar speed = __get_link_speed(port);
24877bb11dc9SMahesh Bandewar ospeed = (old_oper_key & AD_SPEED_KEY_MASKS) >> 1;
24887bb11dc9SMahesh Bandewar duplex = __get_duplex(port);
24897bb11dc9SMahesh Bandewar port->actor_admin_port_key |= (speed << 1) | duplex;
24907bb11dc9SMahesh Bandewar }
24917bb11dc9SMahesh Bandewar port->actor_oper_port_key = port->actor_admin_port_key;
24927bb11dc9SMahesh Bandewar
24937bb11dc9SMahesh Bandewar if (old_oper_key != port->actor_oper_port_key) {
24947bb11dc9SMahesh Bandewar /* Only 'duplex' port participates in LACP */
24957bb11dc9SMahesh Bandewar if (duplex)
24967bb11dc9SMahesh Bandewar port->sm_vars |= AD_PORT_LACP_ENABLED;
24977bb11dc9SMahesh Bandewar else
24987bb11dc9SMahesh Bandewar port->sm_vars &= ~AD_PORT_LACP_ENABLED;
24997bb11dc9SMahesh Bandewar
25007bb11dc9SMahesh Bandewar if (!reset) {
25017bb11dc9SMahesh Bandewar if (!speed) {
250217720981SJarod Wilson slave_err(port->slave->bond->dev,
250317720981SJarod Wilson port->slave->dev,
250417720981SJarod Wilson "speed changed to 0 on port %d\n",
250517720981SJarod Wilson port->actor_port_number);
25067bb11dc9SMahesh Bandewar } else if (duplex && ospeed != speed) {
25077bb11dc9SMahesh Bandewar /* Speed change restarts LACP state-machine */
25087bb11dc9SMahesh Bandewar port->sm_vars |= AD_PORT_BEGIN;
25097bb11dc9SMahesh Bandewar }
25107bb11dc9SMahesh Bandewar }
25117bb11dc9SMahesh Bandewar }
25127bb11dc9SMahesh Bandewar }
25137bb11dc9SMahesh Bandewar
25147bb11dc9SMahesh Bandewar /**
251552bc6716SMahesh Bandewar * bond_3ad_adapter_speed_duplex_changed - handle a slave's speed / duplex
251652bc6716SMahesh Bandewar * change indication
251752bc6716SMahesh Bandewar *
25181da177e4SLinus Torvalds * @slave: slave struct to work on
25191da177e4SLinus Torvalds *
25201da177e4SLinus Torvalds * Handle reselection of aggregator (if needed) for this port.
25211da177e4SLinus Torvalds */
bond_3ad_adapter_speed_duplex_changed(struct slave * slave)252252bc6716SMahesh Bandewar void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
25231da177e4SLinus Torvalds {
25241da177e4SLinus Torvalds struct port *port;
25251da177e4SLinus Torvalds
25263fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
25271da177e4SLinus Torvalds
252871a06c59Sdingtianhong /* if slave is null, the whole port is not initialized */
25291da177e4SLinus Torvalds if (!port->slave) {
253017720981SJarod Wilson slave_warn(slave->bond->dev, slave->dev,
253117720981SJarod Wilson "speed/duplex changed for uninitialized port\n");
25321da177e4SLinus Torvalds return;
25331da177e4SLinus Torvalds }
25341da177e4SLinus Torvalds
2535e470259fSNikolay Aleksandrov spin_lock_bh(&slave->bond->mode_lock);
25367bb11dc9SMahesh Bandewar ad_update_actor_keys(port, false);
2537e292dcaeSMahesh Bandewar spin_unlock_bh(&slave->bond->mode_lock);
253817720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Port %d changed speed/duplex\n",
253917720981SJarod Wilson port->actor_port_number);
25401da177e4SLinus Torvalds }
25411da177e4SLinus Torvalds
25421da177e4SLinus Torvalds /**
25431da177e4SLinus Torvalds * bond_3ad_handle_link_change - handle a slave's link status change indication
25441da177e4SLinus Torvalds * @slave: slave struct to work on
2545a35e5478SLee Jones * @link: whether the link is now up or down
25461da177e4SLinus Torvalds *
25471da177e4SLinus Torvalds * Handle reselection of aggregator (if needed) for this port.
25481da177e4SLinus Torvalds */
bond_3ad_handle_link_change(struct slave * slave,char link)25491da177e4SLinus Torvalds void bond_3ad_handle_link_change(struct slave *slave, char link)
25501da177e4SLinus Torvalds {
25510622cab0SJay Vosburgh struct aggregator *agg;
25521da177e4SLinus Torvalds struct port *port;
25530622cab0SJay Vosburgh bool dummy;
25541da177e4SLinus Torvalds
25553fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
25561da177e4SLinus Torvalds
2557108db736Sdingtianhong /* if slave is null, the whole port is not initialized */
25581da177e4SLinus Torvalds if (!port->slave) {
255917720981SJarod Wilson slave_warn(slave->bond->dev, slave->dev, "link status changed for uninitialized port\n");
25601da177e4SLinus Torvalds return;
25611da177e4SLinus Torvalds }
25621da177e4SLinus Torvalds
2563e470259fSNikolay Aleksandrov spin_lock_bh(&slave->bond->mode_lock);
2564108db736Sdingtianhong /* on link down we are zeroing duplex and speed since
2565108db736Sdingtianhong * some of the adaptors(ce1000.lan) report full duplex/speed
2566108db736Sdingtianhong * instead of N/A(duplex) / 0(speed).
2567108db736Sdingtianhong *
2568108db736Sdingtianhong * on link up we are forcing recheck on the duplex and speed since
2569108db736Sdingtianhong * some of he adaptors(ce1000.lan) report.
2570108db736Sdingtianhong */
25711da177e4SLinus Torvalds if (link == BOND_LINK_UP) {
2572f48127b6SHolger Eitzenberger port->is_enabled = true;
25737bb11dc9SMahesh Bandewar ad_update_actor_keys(port, false);
25741da177e4SLinus Torvalds } else {
25751da177e4SLinus Torvalds /* link has failed */
2576f48127b6SHolger Eitzenberger port->is_enabled = false;
25777bb11dc9SMahesh Bandewar ad_update_actor_keys(port, true);
25781da177e4SLinus Torvalds }
25790622cab0SJay Vosburgh agg = __get_first_agg(port);
25800622cab0SJay Vosburgh ad_agg_selection_logic(agg, &dummy);
25810622cab0SJay Vosburgh
2582e292dcaeSMahesh Bandewar spin_unlock_bh(&slave->bond->mode_lock);
2583e292dcaeSMahesh Bandewar
258417720981SJarod Wilson slave_dbg(slave->bond->dev, slave->dev, "Port %d changed link status to %s\n",
2585108db736Sdingtianhong port->actor_port_number,
258690194264SJoe Perches link == BOND_LINK_UP ? "UP" : "DOWN");
2587108db736Sdingtianhong
2588ee637714SMahesh Bandewar /* RTNL is held and mode_lock is released so it's safe
2589ee637714SMahesh Bandewar * to update slave_array here.
2590ee637714SMahesh Bandewar */
2591ee637714SMahesh Bandewar bond_update_slave_arr(slave->bond, NULL);
25921da177e4SLinus Torvalds }
25931da177e4SLinus Torvalds
25943bf2d28aSVeaceslav Falico /**
25953bf2d28aSVeaceslav Falico * bond_3ad_set_carrier - set link state for bonding master
2596a35e5478SLee Jones * @bond: bonding structure
25973bf2d28aSVeaceslav Falico *
25983bf2d28aSVeaceslav Falico * if we have an active aggregator, we're up, if not, we're down.
25993bf2d28aSVeaceslav Falico * Presumes that we cannot have an active aggregator if there are
26003bf2d28aSVeaceslav Falico * no slaves with link up.
2601ff59c456SJay Vosburgh *
2602031ae4deSJay Vosburgh * This behavior complies with IEEE 802.3 section 43.3.9.
2603031ae4deSJay Vosburgh *
2604ff59c456SJay Vosburgh * Called by bond_set_carrier(). Return zero if carrier state does not
2605ff59c456SJay Vosburgh * change, nonzero if it does.
2606ff59c456SJay Vosburgh */
bond_3ad_set_carrier(struct bonding * bond)2607ff59c456SJay Vosburgh int bond_3ad_set_carrier(struct bonding *bond)
2608ff59c456SJay Vosburgh {
2609655f8919Sstephen hemminger struct aggregator *active;
2610dec1e90eSnikolay@redhat.com struct slave *first_slave;
2611c1bc9644SVeaceslav Falico int ret = 1;
2612655f8919Sstephen hemminger
2613be79bd04Sdingtianhong rcu_read_lock();
2614be79bd04Sdingtianhong first_slave = bond_first_slave_rcu(bond);
2615c1bc9644SVeaceslav Falico if (!first_slave) {
2616c1bc9644SVeaceslav Falico ret = 0;
2617c1bc9644SVeaceslav Falico goto out;
2618c1bc9644SVeaceslav Falico }
26193fdddd85Sdingtianhong active = __get_active_agg(&(SLAVE_AD_INFO(first_slave)->aggregator));
2620655f8919Sstephen hemminger if (active) {
2621655f8919Sstephen hemminger /* are enough slaves available to consider link up? */
26220622cab0SJay Vosburgh if (__agg_active_ports(active) < bond->params.min_links) {
2623655f8919Sstephen hemminger if (netif_carrier_ok(bond->dev)) {
2624655f8919Sstephen hemminger netif_carrier_off(bond->dev);
2625c1bc9644SVeaceslav Falico goto out;
2626655f8919Sstephen hemminger }
2627655f8919Sstephen hemminger } else if (!netif_carrier_ok(bond->dev)) {
2628ff59c456SJay Vosburgh netif_carrier_on(bond->dev);
2629c1bc9644SVeaceslav Falico goto out;
2630ff59c456SJay Vosburgh }
2631c1bc9644SVeaceslav Falico } else if (netif_carrier_ok(bond->dev)) {
2632ff59c456SJay Vosburgh netif_carrier_off(bond->dev);
2633ff59c456SJay Vosburgh }
2634c1bc9644SVeaceslav Falico out:
2635c1bc9644SVeaceslav Falico rcu_read_unlock();
2636c1bc9644SVeaceslav Falico return ret;
2637ff59c456SJay Vosburgh }
2638ff59c456SJay Vosburgh
26391da177e4SLinus Torvalds /**
2640318debd8Snikolay@redhat.com * __bond_3ad_get_active_agg_info - get information of the active aggregator
26411da177e4SLinus Torvalds * @bond: bonding struct to work on
26421da177e4SLinus Torvalds * @ad_info: ad_info struct to fill with the bond's info
26431da177e4SLinus Torvalds *
26441da177e4SLinus Torvalds * Returns: 0 on success
26451da177e4SLinus Torvalds * < 0 on error
26461da177e4SLinus Torvalds */
__bond_3ad_get_active_agg_info(struct bonding * bond,struct ad_info * ad_info)2647318debd8Snikolay@redhat.com int __bond_3ad_get_active_agg_info(struct bonding *bond,
2648318debd8Snikolay@redhat.com struct ad_info *ad_info)
26491da177e4SLinus Torvalds {
26501da177e4SLinus Torvalds struct aggregator *aggregator = NULL;
26513c4c88a1SVeaceslav Falico struct list_head *iter;
26523c4c88a1SVeaceslav Falico struct slave *slave;
26531da177e4SLinus Torvalds struct port *port;
26541da177e4SLinus Torvalds
265547e91f56Sdingtianhong bond_for_each_slave_rcu(bond, slave, iter) {
26563fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
26571da177e4SLinus Torvalds if (port->aggregator && port->aggregator->is_active) {
26581da177e4SLinus Torvalds aggregator = port->aggregator;
26591da177e4SLinus Torvalds break;
26601da177e4SLinus Torvalds }
26611da177e4SLinus Torvalds }
26621da177e4SLinus Torvalds
266321f374c6SJoe Perches if (!aggregator)
266421f374c6SJoe Perches return -1;
266521f374c6SJoe Perches
26661da177e4SLinus Torvalds ad_info->aggregator_id = aggregator->aggregator_identifier;
2667751da2a6SJarod Wilson ad_info->ports = __agg_active_ports(aggregator);
26681da177e4SLinus Torvalds ad_info->actor_key = aggregator->actor_oper_aggregator_key;
26691da177e4SLinus Torvalds ad_info->partner_key = aggregator->partner_oper_aggregator_key;
26702a7c183bSJoe Perches ether_addr_copy(ad_info->partner_system,
26712a7c183bSJoe Perches aggregator->partner_system.mac_addr_value);
26721da177e4SLinus Torvalds return 0;
26731da177e4SLinus Torvalds }
26741da177e4SLinus Torvalds
bond_3ad_get_active_agg_info(struct bonding * bond,struct ad_info * ad_info)2675318debd8Snikolay@redhat.com int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
2676318debd8Snikolay@redhat.com {
2677318debd8Snikolay@redhat.com int ret;
2678318debd8Snikolay@redhat.com
267947e91f56Sdingtianhong rcu_read_lock();
2680318debd8Snikolay@redhat.com ret = __bond_3ad_get_active_agg_info(bond, ad_info);
268147e91f56Sdingtianhong rcu_read_unlock();
2682318debd8Snikolay@redhat.com
2683318debd8Snikolay@redhat.com return ret;
2684318debd8Snikolay@redhat.com }
2685318debd8Snikolay@redhat.com
bond_3ad_lacpdu_recv(const struct sk_buff * skb,struct bonding * bond,struct slave * slave)2686de063b70SEric Dumazet int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
26873aba891dSJiri Pirko struct slave *slave)
26881da177e4SLinus Torvalds {
2689de063b70SEric Dumazet struct lacpdu *lacpdu, _lacpdu;
2690de063b70SEric Dumazet
26913aba891dSJiri Pirko if (skb->protocol != PKT_TYPE_LACPDU)
269286e74986SNikolay Aleksandrov return RX_HANDLER_ANOTHER;
2693b3053251SNeil Horman
2694bb54e589SMahesh Bandewar if (!MAC_ADDRESS_EQUAL(eth_hdr(skb)->h_dest, lacpdu_mcast_addr))
2695bb54e589SMahesh Bandewar return RX_HANDLER_ANOTHER;
2696bb54e589SMahesh Bandewar
2697de063b70SEric Dumazet lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
2698267c095aSNikolay Aleksandrov if (!lacpdu) {
2699267c095aSNikolay Aleksandrov atomic64_inc(&SLAVE_AD_INFO(slave)->stats.lacpdu_illegal_rx);
2700949e7ceaSNikolay Aleksandrov atomic64_inc(&BOND_AD_INFO(bond).stats.lacpdu_illegal_rx);
270186e74986SNikolay Aleksandrov return RX_HANDLER_ANOTHER;
2702267c095aSNikolay Aleksandrov }
2703ab12811cSAndy Gospodarek
2704dadeb61dSNikolay Aleksandrov return bond_3ad_rx_indication(lacpdu, slave);
27051da177e4SLinus Torvalds }
2706ba824a8bSPeter Pan(潘卫平)
27073bf2d28aSVeaceslav Falico /**
27083bf2d28aSVeaceslav Falico * bond_3ad_update_lacp_rate - change the lacp rate
2709a35e5478SLee Jones * @bond: bonding struct
27103bf2d28aSVeaceslav Falico *
2711ba824a8bSPeter Pan(潘卫平) * When modify lacp_rate parameter via sysfs,
2712ba824a8bSPeter Pan(潘卫平) * update actor_oper_port_state of each port.
2713ba824a8bSPeter Pan(潘卫平) *
2714e470259fSNikolay Aleksandrov * Hold bond->mode_lock,
2715ba824a8bSPeter Pan(潘卫平) * so we can modify port->actor_oper_port_state,
2716ba824a8bSPeter Pan(潘卫平) * no matter bond is up or down.
2717ba824a8bSPeter Pan(潘卫平) */
bond_3ad_update_lacp_rate(struct bonding * bond)2718ba824a8bSPeter Pan(潘卫平) void bond_3ad_update_lacp_rate(struct bonding *bond)
2719ba824a8bSPeter Pan(潘卫平) {
2720ba824a8bSPeter Pan(潘卫平) struct port *port = NULL;
27219caff1e7SVeaceslav Falico struct list_head *iter;
2722c509316bSnikolay@redhat.com struct slave *slave;
2723ba824a8bSPeter Pan(潘卫平) int lacp_fast;
2724ba824a8bSPeter Pan(潘卫平)
2725ba824a8bSPeter Pan(潘卫平) lacp_fast = bond->params.lacp_fast;
2726e470259fSNikolay Aleksandrov spin_lock_bh(&bond->mode_lock);
27279caff1e7SVeaceslav Falico bond_for_each_slave(bond, slave, iter) {
27283fdddd85Sdingtianhong port = &(SLAVE_AD_INFO(slave)->port);
2729ba824a8bSPeter Pan(潘卫平) if (lacp_fast)
2730c1e46990SAndy Roulin port->actor_oper_port_state |= LACP_STATE_LACP_TIMEOUT;
2731ba824a8bSPeter Pan(潘卫平) else
2732c1e46990SAndy Roulin port->actor_oper_port_state &= ~LACP_STATE_LACP_TIMEOUT;
2733ba824a8bSPeter Pan(潘卫平) }
2734e470259fSNikolay Aleksandrov spin_unlock_bh(&bond->mode_lock);
2735ba824a8bSPeter Pan(潘卫平) }
2736a258aeacSNikolay Aleksandrov
bond_3ad_stats_size(void)2737a258aeacSNikolay Aleksandrov size_t bond_3ad_stats_size(void)
2738a258aeacSNikolay Aleksandrov {
2739a258aeacSNikolay Aleksandrov return nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_RX */
2740a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_TX */
2741a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_UNKNOWN_RX */
2742a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_ILLEGAL_RX */
2743a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RX */
2744a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_TX */
2745a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RESP_RX */
2746a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_MARKER_RESP_TX */
2747a258aeacSNikolay Aleksandrov nla_total_size_64bit(sizeof(u64)); /* BOND_3AD_STAT_MARKER_UNKNOWN_RX */
2748a258aeacSNikolay Aleksandrov }
2749a258aeacSNikolay Aleksandrov
bond_3ad_stats_fill(struct sk_buff * skb,struct bond_3ad_stats * stats)2750a258aeacSNikolay Aleksandrov int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats)
2751a258aeacSNikolay Aleksandrov {
2752a258aeacSNikolay Aleksandrov u64 val;
2753a258aeacSNikolay Aleksandrov
2754a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->lacpdu_rx);
2755a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_RX, val,
2756a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2757a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2758a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->lacpdu_tx);
2759a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_TX, val,
2760a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2761a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2762a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->lacpdu_unknown_rx);
2763a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_UNKNOWN_RX, val,
2764a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2765a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2766a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->lacpdu_illegal_rx);
2767a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_LACPDU_ILLEGAL_RX, val,
2768a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2769a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2770a258aeacSNikolay Aleksandrov
2771a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->marker_rx);
2772a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RX, val,
2773a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2774a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2775a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->marker_tx);
2776a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_TX, val,
2777a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2778a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2779a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->marker_resp_rx);
2780a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RESP_RX, val,
2781a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2782a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2783a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->marker_resp_tx);
2784a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_RESP_TX, val,
2785a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2786a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2787a258aeacSNikolay Aleksandrov val = atomic64_read(&stats->marker_unknown_rx);
2788a258aeacSNikolay Aleksandrov if (nla_put_u64_64bit(skb, BOND_3AD_STAT_MARKER_UNKNOWN_RX, val,
2789a258aeacSNikolay Aleksandrov BOND_3AD_STAT_PAD))
2790a258aeacSNikolay Aleksandrov return -EMSGSIZE;
2791a258aeacSNikolay Aleksandrov
2792a258aeacSNikolay Aleksandrov return 0;
2793a258aeacSNikolay Aleksandrov }
2794