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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxx>
---
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





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux