summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-setlink.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-12-09 18:49:07 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-12-16 18:00:25 +0100
commitb1d9c504d3a5468fd63932a88709b0dad9e83374 (patch)
tree8b6596e15b908c357a1fe9ed981a2610d3b7aad3 /src/network/networkd-setlink.c
parentnetwork: make activation error critical (diff)
downloadsystemd-b1d9c504d3a5468fd63932a88709b0dad9e83374.tar.xz
systemd-b1d9c504d3a5468fd63932a88709b0dad9e83374.zip
network: wait until the DSA master interface becomes up
This is for the DSA subsystem, which have several stacked interfaces on the master interface. To bring up a stacked interface, it is necessary that the master is already up. See https://github.com/systemd/systemd/issues/7478#issuecomment-348508263. Note this is not necessary for newer kernels which includes https://github.com/torvalds/linux/commit/9d5ef190e5615a7b63af89f88c4106a5bc127974. Fixes #7478.
Diffstat (limited to 'src/network/networkd-setlink.c')
-rw-r--r--src/network/networkd-setlink.c55
1 files changed, 52 insertions, 3 deletions
diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c
index 7de62711c5..2b659e8f36 100644
--- a/src/network/networkd-setlink.c
+++ b/src/network/networkd-setlink.c
@@ -948,6 +948,41 @@ int link_configure_mtu(Link *link) {
return link_request_to_set_mtu(link, mtu);
}
+static int link_up_dsa_slave(Link *link) {
+ Link *master;
+ int r;
+
+ assert(link);
+
+ /* For older kernels (specifically, older than 9d5ef190e5615a7b63af89f88c4106a5bc127974, kernel-5.12),
+ * it is necessary to bring up a DSA slave that its master interface is already up. And bringing up
+ * the slave fails with -ENETDOWN. So, let's bring up the master even if it is not managed by us,
+ * and try to bring up the slave after the master becomes up. */
+
+ if (link->dsa_master_ifindex <= 0)
+ return 0;
+
+ if (!streq_ptr(link->driver, "dsa"))
+ return 0;
+
+ if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
+ return 0;
+
+ if (master->state == LINK_STATE_UNMANAGED) {
+ /* If the DSA master interface is unmanaged, then it will never become up.
+ * Let's request to bring up the master. */
+ r = link_request_to_bring_up_or_down(master, /* up = */ true);
+ if (r < 0)
+ return r;
+ }
+
+ r = link_request_to_bring_up_or_down(link, /* up = */ true);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool on_activate) {
int r;
@@ -958,7 +993,9 @@ static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message
goto on_error;
r = sd_netlink_message_get_errno(m);
- if (r < 0) {
+ if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0)
+ log_link_message_debug_errno(link, m, r, "Could not bring up dsa slave, retrying again after dsa master becomes up");
+ else if (r < 0) {
const char *error_msg;
error_msg = up ?
@@ -1130,9 +1167,21 @@ int link_request_to_activate(Link *link) {
return 0;
}
-static bool link_is_ready_to_bring_up_or_down(Link *link) {
+static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) {
assert(link);
+ if (up && link->dsa_master_ifindex > 0) {
+ Link *master;
+
+ /* The master inteface must be up. See comments in link_up_dsa_slave(). */
+
+ if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
+ return false;
+
+ if (!FLAGS_SET(master->flags, IFF_UP))
+ return false;
+ }
+
if (link->state == LINK_STATE_UNMANAGED)
return true;
@@ -1160,7 +1209,7 @@ int request_process_link_up_or_down(Request *req) {
link = req->link;
up = PTR_TO_INT(req->userdata);
- if (!link_is_ready_to_bring_up_or_down(link))
+ if (!link_is_ready_to_bring_up_or_down(link, up))
return 0;
r = link_up_or_down(link, up, req->netlink_handler);