History

bonding: Add independent control state machine

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.

Aahil Awatramani committed 2 years ago

Commit 240fd401 parent 040067310 files · +234 −8Browse files

Unified · Split

10 files
  1. Documentation/networking/bonding.rst +12 −0
  2. drivers/net/bonding/bond_3ad.c +150 −7
  3. drivers/net/bonding/bond_main.c +1 −0
  4. drivers/net/bonding/bond_netlink.c +16 −0
  5. drivers/net/bonding/bond_options.c +27 −1
  6. include/net/bond_3ad.h +2 −0
  7. include/net/bond_options.h +1 −0
  8. include/net/bonding.h +23 −0
  9. include/uapi/linux/if_link.h +1 −0
  10. tools/include/uapi/linux/if_link.h +1 −0
Documentation/networking/bonding.rst+12−0
@@ -444,6 +444,18 @@ arp_missed_max · 443 unmodified lines
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+150−7
@@ -106,6 +106,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator, · 105 unmodified lines
106106 static void ad_clear_agg(struct aggregator *aggregator);
107107 static void ad_initialize_agg(struct aggregator *aggregator);
108108 static void ad_initialize_port(struct port *port, int lacp_fast);
109+static void ad_enable_collecting(struct port *port);
110+static void ad_disable_distributing(struct port *port,
111+ bool *update_slave_arr);
109112 static void ad_enable_collecting_distributing(struct port *port,
110113 bool *update_slave_arr);
111114 static void ad_disable_collecting_distributing(struct port *port,
@@ -171,9 +174,38 @@ static inline int __agg_has_partner(struct aggregator *agg) · 59 unmodified lines
171174 return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
172175 }
173176
177+/**
178+ * __disable_distributing_port - disable the port's slave for distributing.
179+ * Port will still be able to collect.
180+ * @port: the port we're looking at
181+ *
182+ * This will disable only distributing on the port's slave.
183+ */
184+static void __disable_distributing_port(struct port *port)
185+{
186+ bond_set_slave_tx_disabled_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
187+}
188+
189+/**
190+ * __enable_collecting_port - enable the port's slave for collecting,
191+ * if it's up
192+ * @port: the port we're looking at
193+ *
194+ * This will enable only collecting on the port's slave.
195+ */
196+static void __enable_collecting_port(struct port *port)
197+{
198+ struct slave *slave = port->slave;
199+
200+ if (slave->link == BOND_LINK_UP && bond_slave_is_up(slave))
201+ bond_set_slave_rx_enabled_flags(slave, BOND_SLAVE_NOTIFY_LATER);
202+}
203+
174204 /**
175205 * __disable_port - disable the port's slave
176206 * @port: the port we're looking at
207+ *
208+ * This will disable both collecting and distributing on the port's slave.
177209 */
178210 static inline void __disable_port(struct port *port)
179211 {
@@ -183,6 +215,8 @@ static inline void __disable_port(struct port *port) · 3 unmodified lines
183215 /**
184216 * __enable_port - enable the port's slave, if it's up
185217 * @port: the port we're looking at
218+ *
219+ * This will enable both collecting and distributing on the port's slave.
186220 */
187221 static inline void __enable_port(struct port *port)
188222 {
@@ -193,10 +227,27 @@ static inline void __enable_port(struct port *port) · 4 unmodified lines
193227 }
194228
195229 /**
196− * __port_is_enabled - check if the port's slave is in active state
230+ * __port_move_to_attached_state - check if port should transition back to attached
231+ * state.
232+ * @port: the port we're looking at
233+ */
234+static bool __port_move_to_attached_state(struct port *port)
235+{
236+ if (!(port->sm_vars & AD_PORT_SELECTED) ||
237+ (port->sm_vars & AD_PORT_STANDBY) ||
238+ !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
239+ !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION))
240+ port->sm_mux_state = AD_MUX_ATTACHED;
241+
242+ return port->sm_mux_state == AD_MUX_ATTACHED;
243+}
244+
245+/**
246+ * __port_is_collecting_distributing - check if the port's slave is in the
247+ * combined collecting/distributing state
197248 * @port: the port we're looking at
198249 */
199−static inline int __port_is_enabled(struct port *port)
250+static int __port_is_collecting_distributing(struct port *port)
200251 {
201252 return bond_is_active_slave(port->slave);
202253 }
@@ -942,6 +993,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) · 739 unmodified lines
942993 */
943994 static void ad_mux_machine(struct port *port, bool *update_slave_arr)
944995 {
996+ struct bonding *bond = __get_bond_by_port(port);
945997 mux_states_t last_state;
946998
947999 /* keep current State Machine state to compare later if it was
@@ -999,9 +1051,13 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 51 unmodified lines
9991051 if ((port->sm_vars & AD_PORT_SELECTED) &&
10001052 (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
10011053 !__check_agg_selection_timer(port)) {
1002− if (port->aggregator->is_active)
1003− port->sm_mux_state =
1004− AD_MUX_COLLECTING_DISTRIBUTING;
1054+ if (port->aggregator->is_active) {
1055+ int state = AD_MUX_COLLECTING_DISTRIBUTING;
1056+
1057+ if (!bond->params.coupled_control)
1058+ state = AD_MUX_COLLECTING;
1059+ port->sm_mux_state = state;
1060+ }
10051061 } else if (!(port->sm_vars & AD_PORT_SELECTED) ||
10061062 (port->sm_vars & AD_PORT_STANDBY)) {
10071063 /* if UNSELECTED or STANDBY */
@@ -1019,11 +1075,45 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 11 unmodified lines
10191075 }
10201076 break;
10211077 case AD_MUX_COLLECTING_DISTRIBUTING:
1078+ if (!__port_move_to_attached_state(port)) {
1079+ /* if port state hasn't changed make
1080+ * sure that a collecting distributing
1081+ * port in an active aggregator is enabled
1082+ */
1083+ if (port->aggregator->is_active &&
1084+ !__port_is_collecting_distributing(port)) {
1085+ __enable_port(port);
1086+ *update_slave_arr = true;
1087+ }
1088+ }
1089+ break;
1090+ case AD_MUX_COLLECTING:
1091+ if (!__port_move_to_attached_state(port)) {
1092+ if ((port->sm_vars & AD_PORT_SELECTED) &&
1093+ (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
1094+ (port->partner_oper.port_state & LACP_STATE_COLLECTING)) {
1095+ port->sm_mux_state = AD_MUX_DISTRIBUTING;
1096+ } else {
1097+ /* If port state hasn't changed, make sure that a collecting
1098+ * port is enabled for an active aggregator.
1099+ */
1100+ struct slave *slave = port->slave;
1101+
1102+ if (port->aggregator->is_active &&
1103+ bond_is_slave_rx_disabled(slave)) {
1104+ ad_enable_collecting(port);
1105+ *update_slave_arr = true;
1106+ }
1107+ }
1108+ }
1109+ break;
1110+ case AD_MUX_DISTRIBUTING:
10221111 if (!(port->sm_vars & AD_PORT_SELECTED) ||
10231112 (port->sm_vars & AD_PORT_STANDBY) ||
1113+ !(port->partner_oper.port_state & LACP_STATE_COLLECTING) ||
10241114 !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
10251115 !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) {
1026− port->sm_mux_state = AD_MUX_ATTACHED;
1116+ port->sm_mux_state = AD_MUX_COLLECTING;
10271117 } else {
10281118 /* if port state hasn't changed make
10291119 * sure that a collecting distributing
@@ -1031,7 +1121,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 1 unmodified line
10311121 */
10321122 if (port->aggregator &&
10331123 port->aggregator->is_active &&
1034− !__port_is_enabled(port)) {
1124+ !__port_is_collecting_distributing(port)) {
10351125 __enable_port(port);
10361126 *update_slave_arr = true;
10371127 }
@@ -1082,6 +1172,20 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 44 unmodified lines
10821172 update_slave_arr);
10831173 port->ntt = true;
10841174 break;
1175+ case AD_MUX_COLLECTING:
1176+ port->actor_oper_port_state |= LACP_STATE_COLLECTING;
1177+ port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
1178+ port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1179+ ad_enable_collecting(port);
1180+ ad_disable_distributing(port, update_slave_arr);
1181+ port->ntt = true;
1182+ break;
1183+ case AD_MUX_DISTRIBUTING:
1184+ port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
1185+ port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1186+ ad_enable_collecting_distributing(port,
1187+ update_slave_arr);
1188+ break;
10851189 default:
10861190 break;
10871191 }
@@ -1906,6 +2010,45 @@ static void ad_initialize_port(struct port *port, int lacp_fast) · 818 unmodified lines
19062010 }
19072011 }
19082012
2013+/**
2014+ * ad_enable_collecting - enable a port's receive
2015+ * @port: the port we're looking at
2016+ *
2017+ * Enable @port if it's in an active aggregator
2018+ */
2019+static void ad_enable_collecting(struct port *port)
2020+{
2021+ if (port->aggregator->is_active) {
2022+ struct slave *slave = port->slave;
2023+
2024+ slave_dbg(slave->bond->dev, slave->dev,
2025+ "Enabling collecting on port %d (LAG %d)\n",
2026+ port->actor_port_number,
2027+ port->aggregator->aggregator_identifier);
2028+ __enable_collecting_port(port);
2029+ }
2030+}
2031+
2032+/**
2033+ * ad_disable_distributing - disable a port's transmit
2034+ * @port: the port we're looking at
2035+ * @update_slave_arr: Does slave array need update?
2036+ */
2037+static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
2038+{
2039+ if (port->aggregator &&
2040+ !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system,
2041+ &(null_mac_addr))) {
2042+ slave_dbg(port->slave->bond->dev, port->slave->dev,
2043+ "Disabling distributing on port %d (LAG %d)\n",
2044+ port->actor_port_number,
2045+ port->aggregator->aggregator_identifier);
2046+ __disable_distributing_port(port);
2047+ /* Slave array needs an update */
2048+ *update_slave_arr = true;
2049+ }
2050+}
2051+
19092052 /**
19102053 * ad_enable_collecting_distributing - enable a port's transmit/receive
19112054 * @port: the port we're looking at
drivers/net/bonding/bond_main.c+1−0
@@ -6306,6 +6306,7 @@ static int __init bond_check_params(struct bond_params *params) · 6305 unmodified lines
63066306 params->ad_actor_sys_prio = ad_actor_sys_prio;
63076307 eth_zero_addr(params->ad_actor_system);
63086308 params->ad_user_port_key = ad_user_port_key;
6309+ params->coupled_control = 1;
63096310 if (packets_per_slave > 0) {
63106311 params->reciprocal_packets_per_slave =
63116312 reciprocal_value(packets_per_slave);
drivers/net/bonding/bond_netlink.c+16−0
@@ -122,6 +122,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { · 121 unmodified lines
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[], · 421 unmodified lines
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) · 60 unmodified lines
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, · 153 unmodified lines
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+27−1
@@ -84,7 +84,8 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond, · 83 unmodified lines
8484 const struct bond_opt_value *newval);
8585 static int bond_option_missed_max_set(struct bonding *bond,
8686 const struct bond_opt_value *newval);
87−
87+static int bond_option_coupled_control_set(struct bonding *bond,
88+ const struct bond_opt_value *newval);
8889
8990 static const struct bond_opt_value bond_mode_tbl[] = {
9091 { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
@@ -232,6 +233,12 @@ static const struct bond_opt_value bond_missed_max_tbl[] = { · 141 unmodified lines
232233 { NULL, -1, 0},
233234 };
234235
236+static const struct bond_opt_value bond_coupled_control_tbl[] = {
237+ { "on", 1, BOND_VALFLAG_DEFAULT},
238+ { "off", 0, 0},
239+ { NULL, -1, 0},
240+};
241+
235242 static const struct bond_option bond_opts[BOND_OPT_LAST] = {
236243 [BOND_OPT_MODE] = {
237244 .id = BOND_OPT_MODE,
@@ -496,6 +503,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { · 258 unmodified lines
496503 .desc = "Delay between each peer notification on failover event, in milliseconds",
497504 .values = bond_peer_notif_delay_tbl,
498505 .set = bond_option_peer_notif_delay_set
506+ },
507+ [BOND_OPT_COUPLED_CONTROL] = {
508+ .id = BOND_OPT_COUPLED_CONTROL,
509+ .name = "coupled_control",
510+ .desc = "Opt into using coupled control MUX for LACP states",
511+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
512+ .flags = BOND_OPTFLAG_IFDOWN,
513+ .values = bond_coupled_control_tbl,
514+ .set = bond_option_coupled_control_set,
499515 }
500516 };
501517
@@ -1692,3 +1708,13 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond, · 1190 unmodified lines
16921708 bond->params.ad_user_port_key = newval->value;
16931709 return 0;
16941710 }
1711+
1712+static int bond_option_coupled_control_set(struct bonding *bond,
1713+ const struct bond_opt_value *newval)
1714+{
1715+ netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n",
1716+ newval->string, newval->value);
1717+
1718+ bond->params.coupled_control = newval->value;
1719+ return 0;
1720+}
include/net/bond_3ad.h+2−0
@@ -54,6 +54,8 @@ typedef enum { · 53 unmodified lines
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+1−0
@@ -76,6 +76,7 @@ enum { · 75 unmodified lines
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
include/net/bonding.h+23−0
@@ -148,6 +148,7 @@ struct bond_params { · 147 unmodified lines
148148 #if IS_ENABLED(CONFIG_IPV6)
149149 struct in6_addr ns_targets[BOND_MAX_NS_TARGETS];
150150 #endif
151+ int coupled_control;
151152
152153 /* 2 bytes of padding : see ether_addr_equal_64bits() */
153154 u8 ad_actor_system[ETH_ALEN + 2];
@@ -167,6 +168,7 @@ struct slave { · 13 unmodified lines
167168 u8 backup:1, /* indicates backup slave. Value corresponds with
168169 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
169170 inactive:1, /* indicates inactive slave */
171+ rx_disabled:1, /* indicates whether slave's Rx is disabled */
170172 should_notify:1, /* indicates whether the state changed */
171173 should_notify_link:1; /* indicates whether the link changed */
172174 u8 duplex;
@@ -568,6 +570,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave, · 395 unmodified lines
568570 bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
569571 if (!slave->bond->params.all_slaves_active)
570572 slave->inactive = 1;
573+ if (BOND_MODE(slave->bond) == BOND_MODE_8023AD)
574+ slave->rx_disabled = 1;
575+}
576+
577+static inline void bond_set_slave_tx_disabled_flags(struct slave *slave,
578+ bool notify)
579+{
580+ bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
571581 }
572582
573583 static inline void bond_set_slave_active_flags(struct slave *slave,
@@ -575,6 +585,14 @@ static inline void bond_set_slave_active_flags(struct slave *slave, · 1 unmodified line
575585 {
576586 bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
577587 slave->inactive = 0;
588+ if (BOND_MODE(slave->bond) == BOND_MODE_8023AD)
589+ slave->rx_disabled = 0;
590+}
591+
592+static inline void bond_set_slave_rx_enabled_flags(struct slave *slave,
593+ bool notify)
594+{
595+ slave->rx_disabled = 0;
578596 }
579597
580598 static inline bool bond_is_slave_inactive(struct slave *slave)
@@ -582,6 +600,11 @@ static inline bool bond_is_slave_inactive(struct slave *slave) · 1 unmodified line
582600 return slave->inactive;
583601 }
584602
603+static inline bool bond_is_slave_rx_disabled(struct slave *slave)
604+{
605+ return slave->rx_disabled;
606+}
607+
585608 static inline void bond_propose_link_state(struct slave *slave, int state)
586609 {
587610 slave->link_new_state = state;
include/uapi/linux/if_link.h+1−0
@@ -1505,6 +1505,7 @@ enum { · 1504 unmodified lines
15051505 IFLA_BOND_AD_LACP_ACTIVE,
15061506 IFLA_BOND_MISSED_MAX,
15071507 IFLA_BOND_NS_IP6_TARGET,
1508+ IFLA_BOND_COUPLED_CONTROL,
15081509 __IFLA_BOND_MAX,
15091510 };
15101511
tools/include/uapi/linux/if_link.h+1−0
@@ -974,6 +974,7 @@ enum { · 973 unmodified lines
974974 IFLA_BOND_AD_LACP_ACTIVE,
975975 IFLA_BOND_MISSED_MAX,
976976 IFLA_BOND_NS_IP6_TARGET,
977+ IFLA_BOND_COUPLED_CONTROL,
977978 __IFLA_BOND_MAX,
978979 };
979980