diff mbox series

[net] enic: Avoid removing IPv6 address when updating rings size.

Message ID 20250223214203.2159676-1-mheib@redhat.com (mailing list archive)
State New
Delegated to: Netdev Maintainers
Headers show
Series [net] enic: Avoid removing IPv6 address when updating rings size. | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 4 maintainers not CCed: kuba@kernel.org andrew+netdev@lunn.ch pabeni@redhat.com edumazet@google.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 4 this patch: 4
netdev/checkpatch warning WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest fail net-next-2025-02-24--00-00 (tests: 891)

Commit Message

Mohammad Heib Feb. 23, 2025, 9:42 p.m. UTC
Currently, the enic driver calls the dev_close function to temporarily
shut down the device before updating the device rings. This call
triggers a NETDEV_DOWN event, which is sent to the network stack via the
network notifier.

When the IPv6 stack receives such an event, it removes the IPv6
addresses from the affected device, keeping only the permanent
addresses. This behavior is inconsistent with other network drivers and
can lead to traffic loss, requiring reconfiguration of IPv6 addresses
after every ring update.

To avoid this behavior, this patch temporarily sets the interface config
`keep_addr_on_down` to 1 before closing the device during the rings
update, and restores the original value of `keep_addr_on_down` after
updating the device rings, this will prevent the ipv6 stack from
removing the current ipv6 addresses during the rings update.

Fixes: ed519b7488a4 ("enic: Add support for 'ethtool -g/-G'")
Signed-off-by: Mohammad Heib <mheib@redhat.com>
---
 .../net/ethernet/cisco/enic/enic_ethtool.c    | 27 ++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index d607b4f0542c..0860233ebac6 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -4,6 +4,7 @@ 
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/net_tstamp.h>
+#include <net/addrconf.h>
 
 #include "enic_res.h"
 #include "enic.h"
@@ -235,10 +236,12 @@  static int enic_set_ringparam(struct net_device *netdev,
 {
 	struct enic *enic = netdev_priv(netdev);
 	struct vnic_enet_config *c = &enic->config;
+	struct inet6_dev *idev = NULL;
 	int running = netif_running(netdev);
 	unsigned int rx_pending;
 	unsigned int tx_pending;
 	int err = 0;
+	__s32 old_keep_addr_on_down = 0;
 
 	if (ring->rx_mini_max_pending || ring->rx_mini_pending) {
 		netdev_info(netdev,
@@ -266,8 +269,25 @@  static int enic_set_ringparam(struct net_device *netdev,
 			    ENIC_MAX_WQ_DESCS);
 		return -EINVAL;
 	}
-	if (running)
+	if (running) {
+		/* Temporarily store the old value of keep_addr_on_down for this specific
+		 * device and set it to 1. This ensures that the IPv6 stack call triggered
+		 * by the dev_close function in the next line will not remove the IPv6
+		 * addresses. The keep_addr_on_down value will be restored to its original
+		 * value before calling dev_open, ensuring that this temporary change does
+		 * not affect any future device changes.
+		 *
+		 * The rtnl lock was already acquired in the caller of this function,
+		 * so it is safe to call the function below.
+		 */
+		idev = __in6_dev_get(netdev);
+		if (idev) {
+			old_keep_addr_on_down = idev->cnf.keep_addr_on_down;
+			idev->cnf.keep_addr_on_down = 1;
+		}
 		dev_close(netdev);
+	}
+
 	c->rq_desc_count =
 		ring->rx_pending & 0xffffffe0; /* must be aligned to groups of 32 */
 	c->wq_desc_count =
@@ -282,6 +302,9 @@  static int enic_set_ringparam(struct net_device *netdev,
 	}
 	enic_init_vnic_resources(enic);
 	if (running) {
+		if (idev)
+			idev->cnf.keep_addr_on_down = old_keep_addr_on_down;
+
 		err = dev_open(netdev, NULL);
 		if (err)
 			goto err_out;
@@ -290,6 +313,8 @@  static int enic_set_ringparam(struct net_device *netdev,
 err_out:
 	c->rq_desc_count = rx_pending;
 	c->wq_desc_count = tx_pending;
+	if (idev)
+		idev->cnf.keep_addr_on_down = old_keep_addr_on_down;
 	return err;
 }