Skip to content

Commit 5b05078

Browse files
AahilAgregkh
authored andcommitted
bonding: Add independent control state machine
[ Upstream commit 240fd40 ] Add support for the independent control state machine per IEEE 802.1AX-2008 5.4.15 in addition to the existing implementation of the coupled control state machine. Introduces two new states, AD_MUX_COLLECTING and AD_MUX_DISTRIBUTING in the LACP MUX state machine for separated handling of an initial Collecting state before the Collecting and Distributing state. This enables a port to be in a state where it can receive incoming packets while not still distributing. This is useful for reducing packet loss when a port begins distributing before its partner is able to collect. Added new functions such as bond_set_slave_tx_disabled_flags and bond_set_slave_rx_enabled_flags to precisely manage the port's collecting and distributing states. Previously, there was no dedicated method to disable TX while keeping RX enabled, which this patch addresses. Note that the regular flow process in the kernel's bonding driver remains unaffected by this patch. The extension requires explicit opt-in by the user (in order to ensure no disruptions for existing setups) via netlink support using the new bonding parameter coupled_control. The default value for coupled_control is set to 1 so as to preserve existing behaviour. Signed-off-by: Aahil Awatramani <aahila@google.com> Reviewed-by: Hangbin Liu <liuhangbin@gmail.com> Link: https://lore.kernel.org/r/20240202175858.1573852-1-aahila@google.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Stable-dep-of: 0599640 ("bonding: send LACPDUs periodically in passive mode after receiving partner's LACPDU") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent b0b8376 commit 5b05078

10 files changed

Lines changed: 234 additions & 8 deletions

File tree

Documentation/networking/bonding.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,18 @@ arp_missed_max
444444

445445
The default value is 2, and the allowable range is 1 - 255.
446446

447+
coupled_control
448+
449+
Specifies whether the LACP state machine's MUX in the 802.3ad mode
450+
should have separate Collecting and Distributing states.
451+
452+
This is by implementing the independent control state machine per
453+
IEEE 802.1AX-2008 5.4.15 in addition to the existing coupled control
454+
state machine.
455+
456+
The default value is 1. This setting does not separate the Collecting
457+
and Distributing states, maintaining the bond in coupled control.
458+
447459
downdelay
448460

449461
Specifies the time, in milliseconds, to wait before disabling

drivers/net/bonding/bond_3ad.c

Lines changed: 150 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator,
105105
static void ad_clear_agg(struct aggregator *aggregator);
106106
static void ad_initialize_agg(struct aggregator *aggregator);
107107
static void ad_initialize_port(struct port *port, int lacp_fast);
108+
static void ad_enable_collecting(struct port *port);
109+
static void ad_disable_distributing(struct port *port,
110+
bool *update_slave_arr);
108111
static void ad_enable_collecting_distributing(struct port *port,
109112
bool *update_slave_arr);
110113
static void ad_disable_collecting_distributing(struct port *port,
@@ -170,9 +173,38 @@ static inline int __agg_has_partner(struct aggregator *agg)
170173
return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
171174
}
172175

176+
/**
177+
* __disable_distributing_port - disable the port's slave for distributing.
178+
* Port will still be able to collect.
179+
* @port: the port we're looking at
180+
*
181+
* This will disable only distributing on the port's slave.
182+
*/
183+
static void __disable_distributing_port(struct port *port)
184+
{
185+
bond_set_slave_tx_disabled_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
186+
}
187+
188+
/**
189+
* __enable_collecting_port - enable the port's slave for collecting,
190+
* if it's up
191+
* @port: the port we're looking at
192+
*
193+
* This will enable only collecting on the port's slave.
194+
*/
195+
static void __enable_collecting_port(struct port *port)
196+
{
197+
struct slave *slave = port->slave;
198+
199+
if (slave->link == BOND_LINK_UP && bond_slave_is_up(slave))
200+
bond_set_slave_rx_enabled_flags(slave, BOND_SLAVE_NOTIFY_LATER);
201+
}
202+
173203
/**
174204
* __disable_port - disable the port's slave
175205
* @port: the port we're looking at
206+
*
207+
* This will disable both collecting and distributing on the port's slave.
176208
*/
177209
static inline void __disable_port(struct port *port)
178210
{
@@ -182,6 +214,8 @@ static inline void __disable_port(struct port *port)
182214
/**
183215
* __enable_port - enable the port's slave, if it's up
184216
* @port: the port we're looking at
217+
*
218+
* This will enable both collecting and distributing on the port's slave.
185219
*/
186220
static inline void __enable_port(struct port *port)
187221
{
@@ -192,10 +226,27 @@ static inline void __enable_port(struct port *port)
192226
}
193227

194228
/**
195-
* __port_is_enabled - check if the port's slave is in active state
229+
* __port_move_to_attached_state - check if port should transition back to attached
230+
* state.
231+
* @port: the port we're looking at
232+
*/
233+
static bool __port_move_to_attached_state(struct port *port)
234+
{
235+
if (!(port->sm_vars & AD_PORT_SELECTED) ||
236+
(port->sm_vars & AD_PORT_STANDBY) ||
237+
!(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
238+
!(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION))
239+
port->sm_mux_state = AD_MUX_ATTACHED;
240+
241+
return port->sm_mux_state == AD_MUX_ATTACHED;
242+
}
243+
244+
/**
245+
* __port_is_collecting_distributing - check if the port's slave is in the
246+
* combined collecting/distributing state
196247
* @port: the port we're looking at
197248
*/
198-
static inline int __port_is_enabled(struct port *port)
249+
static int __port_is_collecting_distributing(struct port *port)
199250
{
200251
return bond_is_active_slave(port->slave);
201252
}
@@ -933,6 +984,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
933984
*/
934985
static void ad_mux_machine(struct port *port, bool *update_slave_arr)
935986
{
987+
struct bonding *bond = __get_bond_by_port(port);
936988
mux_states_t last_state;
937989

938990
/* keep current State Machine state to compare later if it was
@@ -990,9 +1042,13 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
9901042
if ((port->sm_vars & AD_PORT_SELECTED) &&
9911043
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
9921044
!__check_agg_selection_timer(port)) {
993-
if (port->aggregator->is_active)
994-
port->sm_mux_state =
995-
AD_MUX_COLLECTING_DISTRIBUTING;
1045+
if (port->aggregator->is_active) {
1046+
int state = AD_MUX_COLLECTING_DISTRIBUTING;
1047+
1048+
if (!bond->params.coupled_control)
1049+
state = AD_MUX_COLLECTING;
1050+
port->sm_mux_state = state;
1051+
}
9961052
} else if (!(port->sm_vars & AD_PORT_SELECTED) ||
9971053
(port->sm_vars & AD_PORT_STANDBY)) {
9981054
/* if UNSELECTED or STANDBY */
@@ -1010,19 +1066,53 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
10101066
}
10111067
break;
10121068
case AD_MUX_COLLECTING_DISTRIBUTING:
1069+
if (!__port_move_to_attached_state(port)) {
1070+
/* if port state hasn't changed make
1071+
* sure that a collecting distributing
1072+
* port in an active aggregator is enabled
1073+
*/
1074+
if (port->aggregator->is_active &&
1075+
!__port_is_collecting_distributing(port)) {
1076+
__enable_port(port);
1077+
*update_slave_arr = true;
1078+
}
1079+
}
1080+
break;
1081+
case AD_MUX_COLLECTING:
1082+
if (!__port_move_to_attached_state(port)) {
1083+
if ((port->sm_vars & AD_PORT_SELECTED) &&
1084+
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
1085+
(port->partner_oper.port_state & LACP_STATE_COLLECTING)) {
1086+
port->sm_mux_state = AD_MUX_DISTRIBUTING;
1087+
} else {
1088+
/* If port state hasn't changed, make sure that a collecting
1089+
* port is enabled for an active aggregator.
1090+
*/
1091+
struct slave *slave = port->slave;
1092+
1093+
if (port->aggregator->is_active &&
1094+
bond_is_slave_rx_disabled(slave)) {
1095+
ad_enable_collecting(port);
1096+
*update_slave_arr = true;
1097+
}
1098+
}
1099+
}
1100+
break;
1101+
case AD_MUX_DISTRIBUTING:
10131102
if (!(port->sm_vars & AD_PORT_SELECTED) ||
10141103
(port->sm_vars & AD_PORT_STANDBY) ||
1104+
!(port->partner_oper.port_state & LACP_STATE_COLLECTING) ||
10151105
!(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
10161106
!(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) {
1017-
port->sm_mux_state = AD_MUX_ATTACHED;
1107+
port->sm_mux_state = AD_MUX_COLLECTING;
10181108
} else {
10191109
/* if port state hasn't changed make
10201110
* sure that a collecting distributing
10211111
* port in an active aggregator is enabled
10221112
*/
10231113
if (port->aggregator &&
10241114
port->aggregator->is_active &&
1025-
!__port_is_enabled(port)) {
1115+
!__port_is_collecting_distributing(port)) {
10261116
__enable_port(port);
10271117
*update_slave_arr = true;
10281118
}
@@ -1073,6 +1163,20 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
10731163
update_slave_arr);
10741164
port->ntt = true;
10751165
break;
1166+
case AD_MUX_COLLECTING:
1167+
port->actor_oper_port_state |= LACP_STATE_COLLECTING;
1168+
port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
1169+
port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1170+
ad_enable_collecting(port);
1171+
ad_disable_distributing(port, update_slave_arr);
1172+
port->ntt = true;
1173+
break;
1174+
case AD_MUX_DISTRIBUTING:
1175+
port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
1176+
port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1177+
ad_enable_collecting_distributing(port,
1178+
update_slave_arr);
1179+
break;
10761180
default:
10771181
break;
10781182
}
@@ -1897,6 +2001,45 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
18972001
}
18982002
}
18992003

2004+
/**
2005+
* ad_enable_collecting - enable a port's receive
2006+
* @port: the port we're looking at
2007+
*
2008+
* Enable @port if it's in an active aggregator
2009+
*/
2010+
static void ad_enable_collecting(struct port *port)
2011+
{
2012+
if (port->aggregator->is_active) {
2013+
struct slave *slave = port->slave;
2014+
2015+
slave_dbg(slave->bond->dev, slave->dev,
2016+
"Enabling collecting on port %d (LAG %d)\n",
2017+
port->actor_port_number,
2018+
port->aggregator->aggregator_identifier);
2019+
__enable_collecting_port(port);
2020+
}
2021+
}
2022+
2023+
/**
2024+
* ad_disable_distributing - disable a port's transmit
2025+
* @port: the port we're looking at
2026+
* @update_slave_arr: Does slave array need update?
2027+
*/
2028+
static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
2029+
{
2030+
if (port->aggregator &&
2031+
!MAC_ADDRESS_EQUAL(&port->aggregator->partner_system,
2032+
&(null_mac_addr))) {
2033+
slave_dbg(port->slave->bond->dev, port->slave->dev,
2034+
"Disabling distributing on port %d (LAG %d)\n",
2035+
port->actor_port_number,
2036+
port->aggregator->aggregator_identifier);
2037+
__disable_distributing_port(port);
2038+
/* Slave array needs an update */
2039+
*update_slave_arr = true;
2040+
}
2041+
}
2042+
19002043
/**
19012044
* ad_enable_collecting_distributing - enable a port's transmit/receive
19022045
* @port: the port we're looking at

drivers/net/bonding/bond_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6310,6 +6310,7 @@ static int bond_check_params(struct bond_params *params)
63106310
params->ad_actor_sys_prio = ad_actor_sys_prio;
63116311
eth_zero_addr(params->ad_actor_system);
63126312
params->ad_user_port_key = ad_user_port_key;
6313+
params->coupled_control = 1;
63136314
if (packets_per_slave > 0) {
63146315
params->reciprocal_packets_per_slave =
63156316
reciprocal_value(packets_per_slave);

drivers/net/bonding/bond_netlink.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
122122
[IFLA_BOND_PEER_NOTIF_DELAY] = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range),
123123
[IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 },
124124
[IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED },
125+
[IFLA_BOND_COUPLED_CONTROL] = { .type = NLA_U8 },
125126
};
126127

127128
static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
@@ -549,6 +550,16 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
549550
return err;
550551
}
551552

553+
if (data[IFLA_BOND_COUPLED_CONTROL]) {
554+
int coupled_control = nla_get_u8(data[IFLA_BOND_COUPLED_CONTROL]);
555+
556+
bond_opt_initval(&newval, coupled_control);
557+
err = __bond_opt_set(bond, BOND_OPT_COUPLED_CONTROL, &newval,
558+
data[IFLA_BOND_COUPLED_CONTROL], extack);
559+
if (err)
560+
return err;
561+
}
562+
552563
return 0;
553564
}
554565

@@ -615,6 +626,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
615626
/* IFLA_BOND_NS_IP6_TARGET */
616627
nla_total_size(sizeof(struct nlattr)) +
617628
nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS +
629+
nla_total_size(sizeof(u8)) + /* IFLA_BOND_COUPLED_CONTROL */
618630
0;
619631
}
620632

@@ -774,6 +786,10 @@ static int bond_fill_info(struct sk_buff *skb,
774786
bond->params.missed_max))
775787
goto nla_put_failure;
776788

789+
if (nla_put_u8(skb, IFLA_BOND_COUPLED_CONTROL,
790+
bond->params.coupled_control))
791+
goto nla_put_failure;
792+
777793
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
778794
struct ad_info info;
779795

drivers/net/bonding/bond_options.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond,
8585
const struct bond_opt_value *newval);
8686
static int bond_option_missed_max_set(struct bonding *bond,
8787
const struct bond_opt_value *newval);
88-
88+
static int bond_option_coupled_control_set(struct bonding *bond,
89+
const struct bond_opt_value *newval);
8990

9091
static const struct bond_opt_value bond_mode_tbl[] = {
9192
{ "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
@@ -233,6 +234,12 @@ static const struct bond_opt_value bond_missed_max_tbl[] = {
233234
{ NULL, -1, 0},
234235
};
235236

237+
static const struct bond_opt_value bond_coupled_control_tbl[] = {
238+
{ "on", 1, BOND_VALFLAG_DEFAULT},
239+
{ "off", 0, 0},
240+
{ NULL, -1, 0},
241+
};
242+
236243
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
237244
[BOND_OPT_MODE] = {
238245
.id = BOND_OPT_MODE,
@@ -497,6 +504,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
497504
.desc = "Delay between each peer notification on failover event, in milliseconds",
498505
.values = bond_peer_notif_delay_tbl,
499506
.set = bond_option_peer_notif_delay_set
507+
},
508+
[BOND_OPT_COUPLED_CONTROL] = {
509+
.id = BOND_OPT_COUPLED_CONTROL,
510+
.name = "coupled_control",
511+
.desc = "Opt into using coupled control MUX for LACP states",
512+
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
513+
.flags = BOND_OPTFLAG_IFDOWN,
514+
.values = bond_coupled_control_tbl,
515+
.set = bond_option_coupled_control_set,
500516
}
501517
};
502518

@@ -1828,3 +1844,13 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond,
18281844
bond->params.ad_user_port_key = newval->value;
18291845
return 0;
18301846
}
1847+
1848+
static int bond_option_coupled_control_set(struct bonding *bond,
1849+
const struct bond_opt_value *newval)
1850+
{
1851+
netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n",
1852+
newval->string, newval->value);
1853+
1854+
bond->params.coupled_control = newval->value;
1855+
return 0;
1856+
}

include/net/bond_3ad.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ typedef enum {
5454
AD_MUX_DETACHED, /* mux machine */
5555
AD_MUX_WAITING, /* mux machine */
5656
AD_MUX_ATTACHED, /* mux machine */
57+
AD_MUX_COLLECTING, /* mux machine */
58+
AD_MUX_DISTRIBUTING, /* mux machine */
5759
AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */
5860
} mux_states_t;
5961

include/net/bond_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum {
7676
BOND_OPT_MISSED_MAX,
7777
BOND_OPT_NS_TARGETS,
7878
BOND_OPT_PRIO,
79+
BOND_OPT_COUPLED_CONTROL,
7980
BOND_OPT_LAST
8081
};
8182

0 commit comments

Comments
 (0)