Received: by 2002:a05:7412:b995:b0:f9:9502:5bb8 with SMTP id it21csp8049800rdb; Thu, 4 Jan 2024 17:36:12 -0800 (PST) X-Google-Smtp-Source: AGHT+IE/xfV34dk+fn0gchSfBOKl98Aeu15X/ZgIcI0O1b8zW4PcP1FcIQqod2gC0kv4Ts6AFnWb X-Received: by 2002:a05:6214:2402:b0:67f:c076:174c with SMTP id fv2-20020a056214240200b0067fc076174cmr2292967qvb.113.1704418572173; Thu, 04 Jan 2024 17:36:12 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1704418572; cv=none; d=google.com; s=arc-20160816; b=y1JhuNaSwNIJIPoceiOQHa0AUF7t+oM/hV8WgK6eQNMj+YHrQw0a2b5s4858zohAf4 0MnHiCQYxvfQ4j+OviGJ4MTosok2E0oA3N5yFk30zZchodxDePMZI0CUB+obkzWChGsA ikUO+iIwuyRbHcqy6sR3i1BJL55/LtqZ+0VUMbycCBdogF65gCwhR361rXX22MSgI8nN 7H/mxNySH3yS3sXpX2KGohNPpmlQ0FfJLtqRLu7FOrXPn2D0ra+Dhr+9+D8/8NbOcb3D H5GDKRcJupgQoTPscW4ZMk9KNmA6XX8AgO98ODRWS0bIJYQSxR9Zwqmy62Ptk+A6HxTK rzwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:content-transfer-encoding:content-id:mime-version :list-unsubscribe:list-subscribe:list-id:precedence:comments :references:in-reply-to:subject:cc:to:from:dkim-signature; bh=aeWIIYGGE7YjcF5UGY2QOc+yAE0JuezDNFugqniXBgc=; fh=04t87oaxV2HDFmxT6PjhONEwpJXpd93KvVq6NPDPCsw=; b=FqjdOaJ3E7jLWQCO9tByzkyrqksI+s8lJh/Mlu4rgBCsimF0X96DtV+BfzVFMufJ42 6iVeeC7QHz/Oy7/+4/hgAsdWK0cRMLTt5y8RC7xaJU+DI56BNMVqHsxH5Ys+s6An2qb4 WoY0/FqV8efS0Xn3KEOs7nWwkgwD4kmEZvtvpOTih8synetvbLKZluMyEfchNlPM0E4s ELswqd/BNjmcSXNxt0/F5xB+nG0j3PnLlrNgErA6wDy0vhyTFEsxoakd/gjJaqJVAuB6 eqb4C5tuDryyZqRaaWDFPTkLoAASVXCb2Xqe7gGzpKSLbaQ1bKnCg1HqHw0hBjMSsNuG qM1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@canonical.com header.s=20210705 header.b=k1dSBUqn; spf=pass (google.com: domain of linux-kernel+bounces-17391-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-17391-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=canonical.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id a10-20020a0c8bca000000b00680503eb91bsi762414qvc.165.2024.01.04.17.36.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jan 2024 17:36:12 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-17391-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@canonical.com header.s=20210705 header.b=k1dSBUqn; spf=pass (google.com: domain of linux-kernel+bounces-17391-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-17391-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=canonical.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id DA8DD1C22205 for ; Fri, 5 Jan 2024 01:36:11 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7AE6920F1; Fri, 5 Jan 2024 01:36:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="k1dSBUqn" X-Original-To: linux-kernel@vger.kernel.org Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 90FD01FA3 for ; Fri, 5 Jan 2024 01:35:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Received: from mail-pf1-f197.google.com (mail-pf1-f197.google.com [209.85.210.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id A8EFE3F18E for ; Fri, 5 Jan 2024 01:35:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1704418549; bh=aeWIIYGGE7YjcF5UGY2QOc+yAE0JuezDNFugqniXBgc=; h=From:To:cc:Subject:In-reply-to:References:MIME-Version: Content-Type:Date:Message-ID; b=k1dSBUqnGj2nOwFw7MSDoq6f8bDyKSb51aTaMyVSRDJRcH+fn7ZWCDQEd9bGo3qmQ kZmRwtcR20Q5t8CDQCdSX7wmVbo06I89eQYCA2UHIRlh+kWJsTdzFZVqHdz+1vPtuN sE9UoUgPvnSMc951roYJ9t0ri1tRX+4jcc0Ku4jy6VDc5S/fe4WnF2F0iRPUeV45rf AvWHSGDFKtLO/5sGuUlZCOmUWk/Nu8Scd5LLpZ5ReBlWHWjz1t4+2VHq77IehrdP19 EPmMNBA29z7EjjVyYEjMgOagYg3A2oRWteeW2PkVP5n2XCSlKOAa23DR+EJVVatrbc JaISiO92G/Tnw== Received: by mail-pf1-f197.google.com with SMTP id d2e1a72fcca58-6d9e845c0fbso1020042b3a.2 for ; Thu, 04 Jan 2024 17:35:49 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704418548; x=1705023348; h=message-id:date:content-transfer-encoding:content-id:mime-version :comments:references:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=aeWIIYGGE7YjcF5UGY2QOc+yAE0JuezDNFugqniXBgc=; b=Ms1nt5romNVwsxN7zGccRACElvuqXfM53DS+teBBmlHx0uf/tcNlJHqQguGKwRc9Ki 4iv4yPEbNEG3U7mrIM35SW8T8kPpja+1pOf3vGUXqCOLAU+l1lS6a3cR5HQAvJ7ZV+Fb sqXJQQGEjtchNngQYn6Ef+M+PvNcKLr6+ThscXpFKCHb8g9xhw8opvvuZ94RC9BQnZC0 gG7RPToFSh5RcUHfqW7QruMqjKuiPK9Ch0xH/qxDOvv2FrVs3SViN97JQQXS3vTUp6wY mdbozxh9BqB1c66fGs+iNKdziGw90Jbzx48CKKMZJHr7PFEwYQfsP3C3esBRFEgD6as/ v7lw== X-Gm-Message-State: AOJu0Yy+v8n8S5mrLJNOp5OtQYKSBwF0H1igj1ylxc4XekopXxc1bzen +gphQyLQzujsqVPLTCufZCvav8ObZXAGPHkZJur3OAt6Sw5W1pyeuAvO0gyhVdzWDHqZXLkcJIw qm+W6kHFbXS80b28nNFTEN7Q3K5XBM72DxF+24I6LxVbBidoM X-Received: by 2002:a05:6a20:6296:b0:18f:97c:825b with SMTP id o22-20020a056a20629600b0018f097c825bmr1060671pze.101.1704418548262; Thu, 04 Jan 2024 17:35:48 -0800 (PST) X-Received: by 2002:a05:6a20:6296:b0:18f:97c:825b with SMTP id o22-20020a056a20629600b0018f097c825bmr1060652pze.101.1704418547793; Thu, 04 Jan 2024 17:35:47 -0800 (PST) Received: from famine.localdomain ([50.125.80.253]) by smtp.gmail.com with ESMTPSA id y3-20020a170902ed4300b001d4ac461a6fsm253884plb.86.2024.01.04.17.35.47 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 04 Jan 2024 17:35:47 -0800 (PST) Received: by famine.localdomain (Postfix, from userid 1000) id DFDEC5FFF6; Thu, 4 Jan 2024 17:35:46 -0800 (PST) Received: from famine (localhost [127.0.0.1]) by famine.localdomain (Postfix) with ESMTP id D7C279F85F; Thu, 4 Jan 2024 17:35:46 -0800 (PST) From: Jay Vosburgh To: Aahil Awatramani cc: David Dillow , Mahesh Bandewar , Andy Gospodarek , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Martin KaFai Lau , Herbert Xu , Daniel Borkmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 2/2 net-next v2] bonding: Extending LACP MUX State Machine to include a Collecting State. In-reply-to: <20240105000632.2484182-2-aahila@google.com> References: <20240105000632.2484182-1-aahila@google.com> <20240105000632.2484182-2-aahila@google.com> Comments: In-reply-to Aahil Awatramani message dated "Fri, 05 Jan 2024 00:06:32 +0000." X-Mailer: MH-E 8.6+git; nmh 1.6; Emacs 29.0.50 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <11224.1704418546.1@famine> Content-Transfer-Encoding: quoted-printable Date: Thu, 04 Jan 2024 17:35:46 -0800 Message-ID: <11225.1704418546@famine> Aahil Awatramani wrote: >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 whe= n >a port begins distributing before its partner is able to collect. >Additionally this also brings the 802.3ad bonding driver's implementation >closer to the LACP specification which already predefined this behaviour, >that is currently the implementation only supports coupled control. I think this last sentence is (a) unclear, and (b) should be first in the paragraph; I'd suggest something like: 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. The Subject should change in a similar way, e.g., "Add independent control state machine." >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 valu= e >for coupled_control is set to 1 so as to preserve existing behaviour. How did you test this to insure that the new logic works correctly against both coupled and independent control implementations? >Signed-off-by: Aahil Awatramani >--- > drivers/net/bonding/bond_3ad.c | 159 +++++++++++++++++++++++++++-- > drivers/net/bonding/bond_main.c | 1 + > drivers/net/bonding/bond_netlink.c | 16 +++ > drivers/net/bonding/bond_options.c | 26 ++++- > include/net/bond_3ad.h | 2 + > include/net/bond_options.h | 1 + > include/net/bonding.h | 23 +++++ > include/uapi/linux/if_link.h | 1 + > tools/include/uapi/linux/if_link.h | 1 + > 9 files changed, 222 insertions(+), 8 deletions(-) > >diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3a= d.c >index c99ffe6c683a..c2a658f2aaa3 100644 >--- a/drivers/net/bonding/bond_3ad.c >+++ b/drivers/net/bonding/bond_3ad.c >@@ -106,6 +106,9 @@ static void ad_agg_selection_logic(struct aggregator = *aggregator, > static void ad_clear_agg(struct aggregator *aggregator); > static void ad_initialize_agg(struct aggregator *aggregator); > static void ad_initialize_port(struct port *port, int lacp_fast); >+static void ad_enable_collecting(struct port *port); >+static void ad_disable_distributing(struct port *port, >+ bool *update_slave_arr); > static void ad_enable_collecting_distributing(struct port *port, > bool *update_slave_arr); > static void ad_disable_collecting_distributing(struct port *port, >@@ -171,9 +174,38 @@ static inline int __agg_has_partner(struct aggregato= r *agg) > return !is_zero_ether_addr(agg->partner_system.mac_addr_value); > } > = >+/** >+ * __disable_distributing_port - disable the port's slave for distributi= ng. >+ * Port will still be able to collect. >+ * @port: the port we're looking at >+ * >+ * This will disable only distributing on the port's slave. >+ */ >+static inline void __disable_distributing_port(struct port *port) >+{ >+ bond_set_slave_tx_disabled_flags(port->slave, BOND_SLAVE_NOTIFY_LATER); >+} >+ >+/** >+ * __enable_collecting_port - enable the port's slave for collecting, >+ * if it's up >+ * @port: the port we're looking at >+ * >+ * This will enable only collecting on the port's slave. >+ */ >+static inline void __enable_collecting_port(struct port *port) >+{ >+ struct slave *slave =3D port->slave; >+ >+ if (slave->link =3D=3D BOND_LINK_UP && bond_slave_is_up(slave)) >+ bond_set_slave_rx_enabled_flags(slave, BOND_SLAVE_NOTIFY_LATER); >+} >+ > /** > * __disable_port - disable the port's slave > * @port: the port we're looking at >+ * >+ * This will disable both collecting and distributing on the port's slav= e. > */ > static inline void __disable_port(struct port *port) > { >@@ -183,6 +215,8 @@ static inline void __disable_port(struct port *port) > /** > * __enable_port - enable the port's slave, if it's up > * @port: the port we're looking at >+ * >+ * This will enable both collecting and distributing on the port's slave= . > */ > static inline void __enable_port(struct port *port) > { >@@ -193,10 +227,24 @@ static inline void __enable_port(struct port *port) > } > = > /** >- * __port_is_enabled - check if the port's slave is in active state >+ * __port_should_mux_attached - check if port should transition back to = attached >+ * state. > * @port: the port we're looking at > */ >-static inline int __port_is_enabled(struct port *port) >+static inline int __port_should_mux_attached(struct port *port) This name seems suboptimal, perhaps __port_should_goto_attached_state? I'll also note that every use of this function then immediately executes "port->sm_mux_state =3D AD_MUX_ATTACHED", this could plausibly be combined into a __port_move_to_attached_state function that returns true or false, e.g., if (__port_should_mux_attached(port)) { port->sm_mux_state =3D AD_MUX_ATTACHED; } else { /* if port state hasn't changed make * sure that a collecting distributing * port in an active aggregator is enabled */ if (port->aggregator && port->aggregator->is_active && would become something like: if (!__port_move_to_attached_state(port)) { /* if port state hasn't changed make * sure that a collecting distributing * port in an active aggregator is enabled */ if (port->aggregator && port->aggregator->is_active && >+{ >+ return !(port->sm_vars & AD_PORT_SELECTED) || >+ (port->sm_vars & AD_PORT_STANDBY) || >+ !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) || >+ !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION); >+} >+ >+/** >+ * __port_is_collecting_distributing - check if the port's slave is in t= he >+ * combined collecting/distributing state >+ * @port: the port we're looking at >+ */ >+static inline int __port_is_collecting_distributing(struct port *port) > { > return bond_is_active_slave(port->slave); > } >@@ -942,6 +990,7 @@ static int ad_marker_send(struct port *port, struct b= ond_marker *marker) > */ > static void ad_mux_machine(struct port *port, bool *update_slave_arr) > { >+ struct bonding *bond =3D __get_bond_by_port(port); > mux_states_t last_state; > = > /* keep current State Machine state to compare later if it was >@@ -999,9 +1048,13 @@ static void ad_mux_machine(struct port *port, bool = *update_slave_arr) > if ((port->sm_vars & AD_PORT_SELECTED) && > (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && > !__check_agg_selection_timer(port)) { >- if (port->aggregator->is_active) >- port->sm_mux_state =3D >- AD_MUX_COLLECTING_DISTRIBUTING; >+ if (port->aggregator->is_active) { >+ int state =3D AD_MUX_COLLECTING_DISTRIBUTING; >+ >+ if (!bond->params.coupled_control) >+ state =3D AD_MUX_COLLECTING; >+ port->sm_mux_state =3D state; >+ } > } else if (!(port->sm_vars & AD_PORT_SELECTED) || > (port->sm_vars & AD_PORT_STANDBY)) { > /* if UNSELECTED or STANDBY */ >@@ -1019,11 +1072,50 @@ static void ad_mux_machine(struct port *port, boo= l *update_slave_arr) > } > break; > case AD_MUX_COLLECTING_DISTRIBUTING: >+ if (__port_should_mux_attached(port)) { >+ port->sm_mux_state =3D AD_MUX_ATTACHED; >+ } else { >+ /* if port state hasn't changed make >+ * sure that a collecting distributing >+ * port in an active aggregator is enabled >+ */ >+ if (port->aggregator && >+ port->aggregator->is_active && Is it possible for port->aggregator to be NULL here? I don't think it's possible for a port to get to this state and not be attached to an aggregator (it has to be SELECTED by this point). This test logic could also be moved into a helper function if the NULL check is necessary. >+ !__port_is_collecting_distributing(port)) { >+ __enable_port(port); >+ *update_slave_arr =3D true; >+ } >+ } >+ break; >+ case AD_MUX_COLLECTING: >+ if (__port_should_mux_attached(port)) { >+ port->sm_mux_state =3D AD_MUX_ATTACHED; >+ } else if ((port->sm_vars & AD_PORT_SELECTED) && >+ (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && >+ (port->partner_oper.port_state & LACP_STATE_COLLECTING)) { >+ port->sm_mux_state =3D AD_MUX_DISTRIBUTING; >+ } else { >+ /* If port state hasn't changed, make sure that a collecting >+ * port is enabled for an active aggregator. >+ */ >+ if (port->aggregator && >+ port->aggregator->is_active) { Same comment as previous. >+ struct slave *slave =3D port->slave; >+ >+ if (bond_is_slave_rx_disabled(slave) !=3D 0) { The "!=3D 0" is superfluous here as bond_is_slave_rx_disabled() returns a boolean. >+ ad_enable_collecting(port); >+ *update_slave_arr =3D true; >+ } >+ } >+ } >+ break; >+ case AD_MUX_DISTRIBUTING: > if (!(port->sm_vars & AD_PORT_SELECTED) || > (port->sm_vars & AD_PORT_STANDBY) || >+ !(port->partner_oper.port_state & LACP_STATE_COLLECTING) || > !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) || > !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) { >- port->sm_mux_state =3D AD_MUX_ATTACHED; >+ port->sm_mux_state =3D AD_MUX_COLLECTING; > } else { > /* if port state hasn't changed make > * sure that a collecting distributing >@@ -1031,7 +1123,7 @@ static void ad_mux_machine(struct port *port, bool = *update_slave_arr) > */ > if (port->aggregator && > port->aggregator->is_active && >- !__port_is_enabled(port)) { >+ !__port_is_collecting_distributing(port)) { > __enable_port(port); > *update_slave_arr =3D true; > } >@@ -1082,6 +1174,20 @@ static void ad_mux_machine(struct port *port, bool= *update_slave_arr) > update_slave_arr); > port->ntt =3D true; > break; >+ case AD_MUX_COLLECTING: >+ port->actor_oper_port_state |=3D LACP_STATE_COLLECTING; >+ port->actor_oper_port_state &=3D ~LACP_STATE_DISTRIBUTING; >+ port->actor_oper_port_state |=3D LACP_STATE_SYNCHRONIZATION; >+ ad_enable_collecting(port); >+ ad_disable_distributing(port, update_slave_arr); >+ port->ntt =3D true; >+ break; >+ case AD_MUX_DISTRIBUTING: >+ port->actor_oper_port_state |=3D LACP_STATE_DISTRIBUTING; >+ port->actor_oper_port_state |=3D LACP_STATE_SYNCHRONIZATION; >+ ad_enable_collecting_distributing(port, >+ update_slave_arr); >+ break; > default: > break; > } >@@ -1906,6 +2012,45 @@ static void ad_initialize_port(struct port *port, = int lacp_fast) > } > } > = >+/** >+ * ad_enable_collecting - enable a port's receive >+ * @port: the port we're looking at >+ * >+ * Enable @port if it's in an active aggregator >+ */ >+static void ad_enable_collecting(struct port *port) >+{ >+ if (port->aggregator->is_active) { >+ struct slave *slave =3D port->slave; >+ >+ slave_dbg(slave->bond->dev, slave->dev, >+ "Enabling collecting on port %d (LAG %d)\n", >+ port->actor_port_number, >+ port->aggregator->aggregator_identifier); >+ __enable_collecting_port(port); >+ } >+} >+ >+/** >+ * ad_disable_distributing - disable a port's transmit >+ * @port: the port we're looking at >+ * @update_slave_arr: Does slave array need update? >+ */ >+static void ad_disable_distributing(struct port *port, bool *update_slav= e_arr) >+{ >+ if (port->aggregator && >+ !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, >+ &(null_mac_addr))) { >+ slave_dbg(port->slave->bond->dev, port->slave->dev, >+ "Disabling distributing on port %d (LAG %d)\n", >+ port->actor_port_number, >+ port->aggregator->aggregator_identifier); >+ __disable_distributing_port(port); >+ /* Slave array needs an update */ >+ *update_slave_arr =3D true; >+ } >+} >+ > /** > * ad_enable_collecting_distributing - enable a port's transmit/receive > * @port: the port we're looking at >diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_m= ain.c >index 8e6cc0e133b7..30f4b0ff01c0 100644 >--- a/drivers/net/bonding/bond_main.c >+++ b/drivers/net/bonding/bond_main.c >@@ -6331,6 +6331,7 @@ static int __init bond_check_params(struct bond_par= ams *params) > params->ad_actor_sys_prio =3D ad_actor_sys_prio; > eth_zero_addr(params->ad_actor_system); > params->ad_user_port_key =3D ad_user_port_key; >+ params->coupled_control =3D 1; > if (packets_per_slave > 0) { > params->reciprocal_packets_per_slave =3D > reciprocal_value(packets_per_slave); >diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bon= d_netlink.c >index cfa74cf8bb1a..29b4c3d1b9b6 100644 >--- a/drivers/net/bonding/bond_netlink.c >+++ b/drivers/net/bonding/bond_netlink.c >@@ -122,6 +122,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_= MAX + 1] =3D { > [IFLA_BOND_PEER_NOTIF_DELAY] =3D NLA_POLICY_FULL_RANGE(NLA_U32, &del= ay_range), > [IFLA_BOND_MISSED_MAX] =3D { .type =3D NLA_U8 }, > [IFLA_BOND_NS_IP6_TARGET] =3D { .type =3D NLA_NESTED }, >+ [IFLA_BOND_COUPLED_CONTROL] =3D { .type =3D NLA_U8 }, > }; > = > static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1= ] =3D { >@@ -549,6 +550,16 @@ static int bond_changelink(struct net_device *bond_d= ev, struct nlattr *tb[], > return err; > } > = >+ if (data[IFLA_BOND_COUPLED_CONTROL]) { >+ int coupled_control =3D nla_get_u8(data[IFLA_BOND_COUPLED_CONTROL]); >+ >+ bond_opt_initval(&newval, coupled_control); >+ err =3D __bond_opt_set(bond, BOND_OPT_COUPLED_CONTROL, &newval, >+ data[IFLA_BOND_COUPLED_CONTROL], extack); >+ if (err) >+ return err; >+ } >+ > return 0; > } > = >@@ -615,6 +626,7 @@ static size_t bond_get_size(const struct net_device *= bond_dev) > /* IFLA_BOND_NS_IP6_TARGET */ > nla_total_size(sizeof(struct nlattr)) + > nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS + >+ nla_total_size(sizeof(u8)) + /* IFLA_BOND_COUPLED_CONTROL */ > 0; > } > = >@@ -774,6 +786,10 @@ static int bond_fill_info(struct sk_buff *skb, > bond->params.missed_max)) > goto nla_put_failure; > = >+ if (nla_put_u8(skb, IFLA_BOND_COUPLED_CONTROL, >+ bond->params.coupled_control)) >+ goto nla_put_failure; >+ > if (BOND_MODE(bond) =3D=3D BOND_MODE_8023AD) { > struct ad_info info; > = >diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bon= d_options.c >index f3f27f0bd2a6..af5d3c57700b 100644 >--- a/drivers/net/bonding/bond_options.c >+++ b/drivers/net/bonding/bond_options.c >@@ -84,7 +84,8 @@ static int bond_option_ad_user_port_key_set(struct bond= ing *bond, > const struct bond_opt_value *newval); > static int bond_option_missed_max_set(struct bonding *bond, > const struct bond_opt_value *newval); >- >+static int bond_option_coupled_control_set(struct bonding *bond, >+ const struct bond_opt_value *newval); > = > static const struct bond_opt_value bond_mode_tbl[] =3D { > { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, >@@ -232,6 +233,12 @@ static const struct bond_opt_value bond_missed_max_t= bl[] =3D { > { NULL, -1, 0}, > }; > = >+static const struct bond_opt_value bond_coupled_control_tbl[] =3D { >+ { "on", 1, BOND_VALFLAG_DEFAULT}, >+ { "off", 0, 0}, >+ { NULL, -1, 0}, >+}; >+ > static const struct bond_option bond_opts[BOND_OPT_LAST] =3D { > [BOND_OPT_MODE] =3D { > .id =3D BOND_OPT_MODE, >@@ -496,6 +503,14 @@ static const struct bond_option bond_opts[BOND_OPT_L= AST] =3D { > .desc =3D "Delay between each peer notification on failover event, in = milliseconds", > .values =3D bond_peer_notif_delay_tbl, > .set =3D bond_option_peer_notif_delay_set >+ }, >+ [BOND_OPT_COUPLED_CONTROL] =3D { >+ .id =3D BOND_OPT_COUPLED_CONTROL, >+ .name =3D "coupled_control", >+ .desc =3D "Opt into using coupled control MUX for LACP states", >+ .unsuppmodes =3D BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), >+ .values =3D bond_coupled_control_tbl, >+ .set =3D bond_option_coupled_control_set, > } > }; > = >@@ -1692,3 +1707,12 @@ static int bond_option_ad_user_port_key_set(struct= bonding *bond, > bond->params.ad_user_port_key =3D newval->value; > return 0; > } >+ >+static int bond_option_coupled_control_set(struct bonding *bond, >+ const struct bond_opt_value *newval) >+{ >+ netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n", >+ newval->string, newval->value); >+ bond->params.coupled_control =3D newval->value; >+ return 0; >+} I believe this should permit changes to coupled_control only if the bond is down, or up with no interfaces attached to it. The two state machines are not interchangable. -J >diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h >index c5e57c6bd873..9ce5ac2bfbad 100644 >--- a/include/net/bond_3ad.h >+++ b/include/net/bond_3ad.h >@@ -54,6 +54,8 @@ typedef enum { > AD_MUX_DETACHED, /* mux machine */ > AD_MUX_WAITING, /* mux machine */ > AD_MUX_ATTACHED, /* mux machine */ >+ AD_MUX_COLLECTING, /* mux machine */ >+ AD_MUX_DISTRIBUTING, /* mux machine */ > AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */ > } mux_states_t; > = >diff --git a/include/net/bond_options.h b/include/net/bond_options.h >index 69292ecc0325..473a0147769e 100644 >--- a/include/net/bond_options.h >+++ b/include/net/bond_options.h >@@ -76,6 +76,7 @@ enum { > BOND_OPT_MISSED_MAX, > BOND_OPT_NS_TARGETS, > BOND_OPT_PRIO, >+ BOND_OPT_COUPLED_CONTROL, > BOND_OPT_LAST > }; > = >diff --git a/include/net/bonding.h b/include/net/bonding.h >index 5b8b1b644a2d..b61fb1aa3a56 100644 >--- a/include/net/bonding.h >+++ b/include/net/bonding.h >@@ -148,6 +148,7 @@ struct bond_params { > #if IS_ENABLED(CONFIG_IPV6) > struct in6_addr ns_targets[BOND_MAX_NS_TARGETS]; > #endif >+ int coupled_control; > = > /* 2 bytes of padding : see ether_addr_equal_64bits() */ > u8 ad_actor_system[ETH_ALEN + 2]; >@@ -167,6 +168,7 @@ struct slave { > u8 backup:1, /* indicates backup slave. Value corresponds with > BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ > inactive:1, /* indicates inactive slave */ >+ rx_disabled:1, /* indicates whether slave's Rx is disabled */ > should_notify:1, /* indicates whether the state changed */ > should_notify_link:1; /* indicates whether the link changed */ > u8 duplex; >@@ -568,6 +570,14 @@ static inline void bond_set_slave_inactive_flags(str= uct slave *slave, > bond_set_slave_state(slave, BOND_STATE_BACKUP, notify); > if (!slave->bond->params.all_slaves_active) > slave->inactive =3D 1; >+ if (BOND_MODE(slave->bond) =3D=3D BOND_MODE_8023AD) >+ slave->rx_disabled =3D 1; >+} >+ >+static inline void bond_set_slave_tx_disabled_flags(struct slave *slave, >+ bool notify) >+{ >+ bond_set_slave_state(slave, BOND_STATE_BACKUP, notify); > } > = > static inline void bond_set_slave_active_flags(struct slave *slave, >@@ -575,6 +585,14 @@ static inline void bond_set_slave_active_flags(struc= t slave *slave, > { > bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify); > slave->inactive =3D 0; >+ if (BOND_MODE(slave->bond) =3D=3D BOND_MODE_8023AD) >+ slave->rx_disabled =3D 0; >+} >+ >+static inline void bond_set_slave_rx_enabled_flags(struct slave *slave, >+ bool notify) >+{ >+ slave->rx_disabled =3D 0; > } > = > static inline bool bond_is_slave_inactive(struct slave *slave) >@@ -582,6 +600,11 @@ static inline bool bond_is_slave_inactive(struct sla= ve *slave) > return slave->inactive; > } > = >+static inline bool bond_is_slave_rx_disabled(struct slave *slave) >+{ >+ return slave->rx_disabled; >+} >+ > static inline void bond_propose_link_state(struct slave *slave, int stat= e) > { > slave->link_new_state =3D state; >diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h >index 29ff80da2775..7a54fcff2eec 100644 >--- a/include/uapi/linux/if_link.h >+++ b/include/uapi/linux/if_link.h >@@ -976,6 +976,7 @@ enum { > IFLA_BOND_AD_LACP_ACTIVE, > IFLA_BOND_MISSED_MAX, > IFLA_BOND_NS_IP6_TARGET, >+ IFLA_BOND_COUPLED_CONTROL, > __IFLA_BOND_MAX, > }; > = >diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linu= x/if_link.h >index a0aa05a28cf2..f0d71b2a3f1e 100644 >--- a/tools/include/uapi/linux/if_link.h >+++ b/tools/include/uapi/linux/if_link.h >@@ -974,6 +974,7 @@ enum { > IFLA_BOND_AD_LACP_ACTIVE, > IFLA_BOND_MISSED_MAX, > IFLA_BOND_NS_IP6_TARGET, >+ IFLA_BOND_COUPLED_CONTROL, > __IFLA_BOND_MAX, > }; > = >-- = >2.43.0.472.g3155946c3a-goog > > --- -Jay Vosburgh, jay.vosburgh@canonical.com