[PATCH v2 1/3] net: ifup: have ifup -a poll for link up in parallel

Ahmad Fatoum a.fatoum at pengutronix.de
Sun Jan 29 23:20:55 PST 2023


DHCP is usually fairly quick, but link up check timeout is 10 seconds,
which adds up, especially on systems with bigger DSA switches.

The workaround is to set ethX.mode=disabled for other ports, but let's
improve the default a bit and have barebox poll link ups in parallel, so
instead of (number_of_ports_wihout_link * 10s), we just wait 10s at
most.

For setups where this is a problem, users may revert to ifup in sequence
by doing ifup -a -s.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - new patch
---
 include/net.h |   3 ++
 net/eth.c     |  28 ++++++++++----
 net/ifup.c    | 103 ++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 105 insertions(+), 29 deletions(-)

diff --git a/include/net.h b/include/net.h
index 0555b0bd6bed..a7da282412fa 100644
--- a/include/net.h
+++ b/include/net.h
@@ -109,6 +109,7 @@ static inline int eth_send_raw(struct eth_device *edev, void *packet,
 int eth_register(struct eth_device* dev);    /* Register network device		*/
 void eth_unregister(struct eth_device* dev); /* Unregister network device	*/
 int eth_set_ethaddr(struct eth_device *edev, const char *ethaddr);
+int eth_carrier_poll_once(struct eth_device *edev);
 int eth_open(struct eth_device *edev);
 void eth_close(struct eth_device *edev);
 int eth_send(struct eth_device *edev, void *packet, int length);	   /* Send a packet		*/
@@ -511,6 +512,8 @@ int net_icmp_send(struct net_connection *con, int len);
 void led_trigger_network(enum led_trigger trigger);
 
 #define IFUP_FLAG_FORCE		(1 << 0)
+#define IFUP_FLAG_PARALLEL	(1 << 1)
+#define IFUP_FLAG_SKIP_CONF	(1 << 2)
 
 int ifup_edev(struct eth_device *edev, unsigned flags);
 int ifup(const char *name, unsigned flags);
diff --git a/net/eth.c b/net/eth.c
index 6fb64afea024..ccac5e2a6488 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -176,13 +176,29 @@ int eth_complete(struct string_list *sl, char *instr)
 }
 #endif
 
+int eth_carrier_poll_once(struct eth_device *edev)
+{
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_PHYLIB))
+		return 0;
+
+	if (!edev->phydev)
+		return 0;
+
+	ret = phy_update_status(edev->phydev);
+	if (ret)
+		return ret;
+
+	edev->last_link_check = get_time_ns();
+	return edev->phydev->link ? 0 : -ENETDOWN;
+}
+
 /*
  * Check for link if we haven't done so for longer.
  */
 static int eth_carrier_check(struct eth_device *edev, bool may_wait)
 {
-	int ret;
-
 	if (!IS_ENABLED(CONFIG_PHYLIB))
 		return 0;
 
@@ -190,12 +206,8 @@ static int eth_carrier_check(struct eth_device *edev, bool may_wait)
 		return 0;
 
 	if (!edev->last_link_check ||
-	    is_timeout(edev->last_link_check, 5 * SECOND)) {
-		ret = phy_update_status(edev->phydev);
-		if (ret)
-			return ret;
-		edev->last_link_check = get_time_ns();
-	}
+	    is_timeout(edev->last_link_check, 5 * SECOND))
+		eth_carrier_poll_once(edev);
 
 	if (may_wait && !edev->phydev->link) {
 		phy_wait_aneg_done(edev->phydev);
diff --git a/net/ifup.c b/net/ifup.c
index e4d5374db3ae..c491ea03c1c8 100644
--- a/net/ifup.c
+++ b/net/ifup.c
@@ -179,6 +179,28 @@ static void set_linux_bootarg(struct eth_device *edev)
 	}
 }
 
+static int ifup_edev_conf(struct eth_device *edev, unsigned flags)
+{
+	int ret;
+
+	if (edev->global_mode == ETH_MODE_DHCP) {
+		if (IS_ENABLED(CONFIG_NET_DHCP)) {
+			ret = dhcp(edev, NULL);
+		} else {
+			dev_err(&edev->dev, "DHCP support not available\n");
+			ret = -ENOSYS;
+		}
+		if (ret)
+			return ret;
+	}
+
+	set_linux_bootarg(edev);
+
+	edev->ifup = true;
+
+	return 0;
+}
+
 int ifup_edev(struct eth_device *edev, unsigned flags)
 {
 	int ret;
@@ -205,22 +227,10 @@ int ifup_edev(struct eth_device *edev, unsigned flags)
 	if (ret)
 		return ret;
 
-	if (edev->global_mode == ETH_MODE_DHCP) {
-		if (IS_ENABLED(CONFIG_NET_DHCP)) {
-			ret = dhcp(edev, NULL);
-		} else {
-			dev_err(&edev->dev, "DHCP support not available\n");
-			ret = -ENOSYS;
-		}
-		if (ret)
-			return ret;
-	}
-
-	set_linux_bootarg(edev);
-
-	edev->ifup = true;
+	if (flags & IFUP_FLAG_SKIP_CONF)
+		return 1;
 
-	return 0;
+	return ifup_edev_conf(edev, flags);
 }
 
 void ifdown_edev(struct eth_device *edev)
@@ -260,9 +270,54 @@ int ifdown(const char *ethname)
 
 static int net_ifup_force_detect;
 
-int ifup_all(unsigned flags)
+static bool ifup_edev_need_conf(struct eth_device *edev)
+{
+	return edev->active && !edev->ifup &&
+		edev->global_mode != ETH_MODE_DISABLED;
+}
+
+static void __ifup_all_parallel(unsigned flags)
 {
 	struct eth_device *edev;
+	unsigned netdev_count = 0;
+	u64 start;
+	int ret;
+
+	for_each_netdev(edev) {
+		ret = ifup_edev(edev, flags | IFUP_FLAG_SKIP_CONF);
+		if (ret == 1)
+			netdev_count++;
+	}
+
+	start = get_time_ns();
+	while (netdev_count && !is_timeout(start, PHY_AN_TIMEOUT * SECOND)) {
+		for_each_netdev(edev) {
+			if (!ifup_edev_need_conf(edev))
+				continue;
+
+			ret = eth_carrier_poll_once(edev);
+			if (ret)
+				continue;
+
+			ifup_edev_conf(edev, flags);
+			if (!edev->ifup)
+				continue;
+
+			netdev_count--;
+		}
+	}
+}
+
+static void __ifup_all_sequence(unsigned flags)
+{
+	struct eth_device *edev;
+
+	for_each_netdev(edev)
+		ifup_edev(edev, flags);
+}
+
+int ifup_all(unsigned flags)
+{
 	DIR *dir;
 	struct dirent *d;
 
@@ -285,8 +340,10 @@ int ifup_all(unsigned flags)
 	    list_empty(&netdev_list))
 		device_detect_all();
 
-	for_each_netdev(edev)
-		ifup_edev(edev, flags);
+	if (flags & IFUP_FLAG_PARALLEL)
+		__ifup_all_parallel(flags);
+	else
+		__ifup_all_sequence(flags);
 
 	return 0;
 }
@@ -315,14 +372,17 @@ BAREBOX_MAGICVAR(global.net.ifup_force_detect,
 static int do_ifup(int argc, char *argv[])
 {
 	int opt;
-	unsigned flags = 0;
+	unsigned flags = IFUP_FLAG_PARALLEL;
 	int all = 0;
 
-	while ((opt = getopt(argc, argv, "af")) > 0) {
+	while ((opt = getopt(argc, argv, "asf")) > 0) {
 		switch (opt) {
 		case 'f':
 			flags |= IFUP_FLAG_FORCE;
 			break;
+		case 's':
+			flags &= ~IFUP_FLAG_PARALLEL;
+			break;
 		case 'a':
 			all = 1;
 			break;
@@ -346,13 +406,14 @@ BAREBOX_CMD_HELP_TEXT("/env/network/<intf> file. See Documentation/user/networki
 BAREBOX_CMD_HELP_TEXT("")
 BAREBOX_CMD_HELP_TEXT("Options:")
 BAREBOX_CMD_HELP_OPT ("-a",  "bring up all interfaces")
+BAREBOX_CMD_HELP_OPT ("-s",  "bring up interfaces in sequence, not in parallel")
 BAREBOX_CMD_HELP_OPT ("-f",  "Force. Configure even if ip already set")
 BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(ifup)
 	.cmd		= do_ifup,
 	BAREBOX_CMD_DESC("bring a network interface up")
-	BAREBOX_CMD_OPTS("[-af] [INTF]")
+	BAREBOX_CMD_OPTS("[-asf] [INTF]")
 	BAREBOX_CMD_GROUP(CMD_GRP_NET)
 	BAREBOX_CMD_COMPLETE(eth_complete)
 	BAREBOX_CMD_HELP(cmd_ifup_help)
-- 
2.30.2




More information about the barebox mailing list