Skip to content

Commit 4f58c0b

Browse files
liuhangbingregkh
authored andcommitted
bonding: send LACPDUs periodically in passive mode after receiving partner's LACPDU
[ Upstream commit 0599640 ] When `lacp_active` is set to `off`, the bond operates in passive mode, meaning it only "speaks when spoken to." However, the current kernel implementation only sends an LACPDU in response when the partner's state changes. As a result, once LACP negotiation succeeds, the actor stops sending LACPDUs until the partner times out and sends an "expired" LACPDU. This causes continuous LACP state flapping. According to IEEE 802.1AX-2014, 6.4.13 Periodic Transmission machine. The values of Partner_Oper_Port_State.LACP_Activity and Actor_Oper_Port_State.LACP_Activity determine whether periodic transmissions take place. If either or both parameters are set to Active LACP, then periodic transmissions occur; if both are set to Passive LACP, then periodic transmissions do not occur. To comply with this, we remove the `!bond->params.lacp_active` check in `ad_periodic_machine()`. Instead, we initialize the actor's port's `LACP_STATE_LACP_ACTIVITY` state based on `lacp_active` setting. Additionally, we avoid setting the partner's state to `LACP_STATE_LACP_ACTIVITY` in the EXPIRED state, since we should not assume the partner is active by default. This ensures that in passive mode, the bond starts sending periodic LACPDUs after receiving one from the partner, and avoids flapping due to inactivity. Fixes: 3a755cd ("bonding: add new option lacp_active") Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Link: https://patch.msgid.link/20250815062000.22220-3-liuhangbin@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 3310f0e commit 4f58c0b

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

drivers/net/bonding/bond_3ad.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker);
9595
static void ad_mux_machine(struct port *port, bool *update_slave_arr);
9696
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
9797
static void ad_tx_machine(struct port *port);
98-
static void ad_periodic_machine(struct port *port, struct bond_params *bond_params);
98+
static void ad_periodic_machine(struct port *port);
9999
static void ad_port_selection_logic(struct port *port, bool *update_slave_arr);
100100
static void ad_agg_selection_logic(struct aggregator *aggregator,
101101
bool *update_slave_arr);
102102
static void ad_clear_agg(struct aggregator *aggregator);
103103
static void ad_initialize_agg(struct aggregator *aggregator);
104-
static void ad_initialize_port(struct port *port, int lacp_fast);
104+
static void ad_initialize_port(struct port *port, const struct bond_params *bond_params);
105105
static void ad_enable_collecting(struct port *port);
106106
static void ad_disable_distributing(struct port *port,
107107
bool *update_slave_arr);
@@ -1296,10 +1296,16 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
12961296
* case of EXPIRED even if LINK_DOWN didn't arrive for
12971297
* the port.
12981298
*/
1299-
port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION;
13001299
port->sm_vars &= ~AD_PORT_MATCHED;
1300+
/* Based on IEEE 8021AX-2014, Figure 6-18 - Receive
1301+
* machine state diagram, the statue should be
1302+
* Partner_Oper_Port_State.Synchronization = FALSE;
1303+
* Partner_Oper_Port_State.LACP_Timeout = Short Timeout;
1304+
* start current_while_timer(Short Timeout);
1305+
* Actor_Oper_Port_State.Expired = TRUE;
1306+
*/
1307+
port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION;
13011308
port->partner_oper.port_state |= LACP_STATE_LACP_TIMEOUT;
1302-
port->partner_oper.port_state |= LACP_STATE_LACP_ACTIVITY;
13031309
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
13041310
port->actor_oper_port_state |= LACP_STATE_EXPIRED;
13051311
port->sm_vars |= AD_PORT_CHURNED;
@@ -1405,11 +1411,10 @@ static void ad_tx_machine(struct port *port)
14051411
/**
14061412
* ad_periodic_machine - handle a port's periodic state machine
14071413
* @port: the port we're looking at
1408-
* @bond_params: bond parameters we will use
14091414
*
14101415
* Turn ntt flag on priodically to perform periodic transmission of lacpdu's.
14111416
*/
1412-
static void ad_periodic_machine(struct port *port, struct bond_params *bond_params)
1417+
static void ad_periodic_machine(struct port *port)
14131418
{
14141419
periodic_states_t last_state;
14151420

@@ -1418,8 +1423,7 @@ static void ad_periodic_machine(struct port *port, struct bond_params *bond_para
14181423

14191424
/* check if port was reinitialized */
14201425
if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
1421-
(!(port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & LACP_STATE_LACP_ACTIVITY)) ||
1422-
!bond_params->lacp_active) {
1426+
(!(port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & LACP_STATE_LACP_ACTIVITY))) {
14231427
port->sm_periodic_state = AD_NO_PERIODIC;
14241428
}
14251429
/* check if state machine should change state */
@@ -1943,16 +1947,16 @@ static void ad_initialize_agg(struct aggregator *aggregator)
19431947
/**
19441948
* ad_initialize_port - initialize a given port's parameters
19451949
* @port: the port we're looking at
1946-
* @lacp_fast: boolean. whether fast periodic should be used
1950+
* @bond_params: bond parameters we will use
19471951
*/
1948-
static void ad_initialize_port(struct port *port, int lacp_fast)
1952+
static void ad_initialize_port(struct port *port, const struct bond_params *bond_params)
19491953
{
19501954
static const struct port_params tmpl = {
19511955
.system_priority = 0xffff,
19521956
.key = 1,
19531957
.port_number = 1,
19541958
.port_priority = 0xff,
1955-
.port_state = 1,
1959+
.port_state = 0,
19561960
};
19571961
static const struct lacpdu lacpdu = {
19581962
.subtype = 0x01,
@@ -1970,12 +1974,14 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
19701974
port->actor_port_priority = 0xff;
19711975
port->actor_port_aggregator_identifier = 0;
19721976
port->ntt = false;
1973-
port->actor_admin_port_state = LACP_STATE_AGGREGATION |
1974-
LACP_STATE_LACP_ACTIVITY;
1975-
port->actor_oper_port_state = LACP_STATE_AGGREGATION |
1976-
LACP_STATE_LACP_ACTIVITY;
1977+
port->actor_admin_port_state = LACP_STATE_AGGREGATION;
1978+
port->actor_oper_port_state = LACP_STATE_AGGREGATION;
1979+
if (bond_params->lacp_active) {
1980+
port->actor_admin_port_state |= LACP_STATE_LACP_ACTIVITY;
1981+
port->actor_oper_port_state |= LACP_STATE_LACP_ACTIVITY;
1982+
}
19771983

1978-
if (lacp_fast)
1984+
if (bond_params->lacp_fast)
19791985
port->actor_oper_port_state |= LACP_STATE_LACP_TIMEOUT;
19801986

19811987
memcpy(&port->partner_admin, &tmpl, sizeof(tmpl));
@@ -2187,7 +2193,7 @@ void bond_3ad_bind_slave(struct slave *slave)
21872193
/* port initialization */
21882194
port = &(SLAVE_AD_INFO(slave)->port);
21892195

2190-
ad_initialize_port(port, bond->params.lacp_fast);
2196+
ad_initialize_port(port, &bond->params);
21912197

21922198
port->slave = slave;
21932199
port->actor_port_number = SLAVE_AD_INFO(slave)->id;
@@ -2499,7 +2505,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
24992505
}
25002506

25012507
ad_rx_machine(NULL, port);
2502-
ad_periodic_machine(port, &bond->params);
2508+
ad_periodic_machine(port);
25032509
ad_port_selection_logic(port, &update_slave_arr);
25042510
ad_mux_machine(port, &update_slave_arr);
25052511
ad_tx_machine(port);

0 commit comments

Comments
 (0)