summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/netdev/netdev.c2
-rw-r--r--src/network/networkd-can.c37
-rw-r--r--src/network/networkd-link.c103
-rw-r--r--src/network/networkd-link.h3
-rw-r--r--src/network/networkd-queue.c15
-rw-r--r--src/network/networkd-queue.h1
-rw-r--r--src/network/networkd-setlink.c157
-rw-r--r--src/network/networkd-setlink.h6
8 files changed, 196 insertions, 128 deletions
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index a0b6706aad..5c1927cdfc 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -272,7 +272,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message
if (link->flags & IFF_UP && netdev->kind == NETDEV_KIND_BOND) {
log_netdev_debug(netdev, "Link '%s' was up when attempting to enslave it. Bringing link down.", link->ifname);
- r = link_down(link, NULL);
+ r = link_down(link);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not bring link down: %m");
}
diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c
index 787cfd711e..41b946b44d 100644
--- a/src/network/networkd-can.c
+++ b/src/network/networkd-can.c
@@ -7,6 +7,7 @@
#include "networkd-can.h"
#include "networkd-link.h"
#include "networkd-manager.h"
+#include "networkd-setlink.h"
#include "parse-util.h"
#include "string-util.h"
@@ -229,28 +230,6 @@ static int link_set_can(Link *link) {
return 0;
}
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(link);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0) {
- log_link_message_warning_errno(link, m, r, "Could not bring down interface");
- link_enter_failed(link);
- return 1;
- }
-
- r = link_set_can(link);
- if (r < 0)
- link_enter_failed(link);
-
- return 1;
-}
-
int link_configure_can(Link *link) {
int r;
@@ -258,13 +237,13 @@ int link_configure_can(Link *link) {
if (streq_ptr(link->kind, "can")) {
/* The CAN interface must be down to configure bitrate, etc... */
- if ((link->flags & IFF_UP))
- r = link_down(link, link_down_handler);
- else
- r = link_set_can(link);
- if (r < 0)
- link_enter_failed(link);
- return r;
+ if (link->flags & IFF_UP) {
+ r = link_down(link);
+ if (r < 0)
+ return r;
+ }
+
+ return link_set_can(link);
}
r = link_activate(link);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 7570775744..00bcb5b0bc 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -159,6 +159,11 @@ bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
return false;
*/
+ /* TODO: enable this check when link_request_to_activate() is used.
+ if (!link->activated)
+ return false;
+ */
+
return true;
}
@@ -754,97 +759,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
return 0;
}
-static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(link);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0)
- /* we warn but don't fail the link, as it may be brought up later */
- log_link_message_warning_errno(link, m, r, "Could not bring up interface");
-
- return 1;
-}
-
-int link_up(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- int r;
-
- assert(link);
- assert(link->network);
- assert(link->manager);
- assert(link->manager->rtnl);
-
- log_link_debug(link, "Bringing link up");
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
- r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set link flags: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- return 0;
-}
-
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(link);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0)
- log_link_message_warning_errno(link, m, r, "Could not bring down interface");
-
- return 1;
-}
-
-int link_down(Link *link, link_netlink_message_handler_t callback) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- int r;
-
- assert(link);
- assert(link->manager);
- assert(link->manager->rtnl);
-
- log_link_debug(link, "Bringing link down");
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
- r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set link flags: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req,
- callback ?: link_down_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- return 0;
-}
-
-static int link_handle_bound_to_list(Link *link) {
+int link_handle_bound_to_list(Link *link) {
bool required_up = false;
bool link_is_up = false;
Link *l;
@@ -864,7 +779,7 @@ static int link_handle_bound_to_list(Link *link) {
}
if (!required_up && link_is_up)
- return link_down(link, NULL);
+ return link_down(link);
if (required_up && !link_is_up)
return link_up(link);
@@ -1141,7 +1056,7 @@ int link_activate(Link *link) {
break;
_fallthrough_;
case ACTIVATION_POLICY_ALWAYS_DOWN:
- r = link_down(link, NULL);
+ r = link_down(link);
if (r < 0)
return r;
break;
@@ -1945,7 +1860,7 @@ static int link_admin_state_up(Link *link) {
if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN) {
log_link_info(link, "ActivationPolicy is \"always-off\", forcing link down");
- return link_down(link, NULL);
+ return link_down(link);
}
/* We set the ipv6 mtu after the device mtu, but the kernel resets
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 600b5f5ee1..15a0cdd7d0 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -224,9 +224,8 @@ int link_get_master(Link *link, Link **ret);
int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int link_call_getlink(Link *link, link_netlink_message_handler_t callback);
-int link_up(Link *link);
-int link_down(Link *link, link_netlink_message_handler_t callback);
int link_activate(Link *link);
+int link_handle_bound_to_list(Link *link);
int link_enter_join_netdev(Link *link);
void link_enter_failed(Link *link);
diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c
index 3a17a06b2c..acda4994f0 100644
--- a/src/network/networkd-queue.c
+++ b/src/network/networkd-queue.c
@@ -15,6 +15,8 @@
static void request_free_object(RequestType type, void *object) {
switch(type) {
+ case REQUEST_TYPE_ACTIVATE_LINK:
+ break;
case REQUEST_TYPE_ADDRESS:
address_free(object);
break;
@@ -89,6 +91,8 @@ static void request_hash_func(const Request *req, struct siphash *state) {
siphash24_compress(&req->type, sizeof(req->type), state);
switch(req->type) {
+ case REQUEST_TYPE_ACTIVATE_LINK:
+ break;
case REQUEST_TYPE_ADDRESS:
address_hash_func(req->address, state);
break;
@@ -143,6 +147,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
return r;
switch (a->type) {
+ case REQUEST_TYPE_ACTIVATE_LINK:
+ return 0;
case REQUEST_TYPE_ADDRESS:
return address_compare_func(a->address, b->address);
case REQUEST_TYPE_ADDRESS_LABEL:
@@ -192,7 +198,11 @@ int link_queue_request(
assert(link);
assert(link->manager);
assert(type >= 0 && type < _REQUEST_TYPE_MAX);
- assert(IN_SET(type, REQUEST_TYPE_DHCP_SERVER, REQUEST_TYPE_SET_LINK) || object);
+ assert(IN_SET(type,
+ REQUEST_TYPE_ACTIVATE_LINK,
+ REQUEST_TYPE_DHCP_SERVER,
+ REQUEST_TYPE_SET_LINK) ||
+ object);
assert(type == REQUEST_TYPE_DHCP_SERVER || netlink_handler);
req = new(Request, 1);
@@ -247,6 +257,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
ORDERED_SET_FOREACH(req, manager->request_queue) {
switch(req->type) {
+ case REQUEST_TYPE_ACTIVATE_LINK:
+ r = request_process_activation(req);
+ break;
case REQUEST_TYPE_ADDRESS:
r = request_process_address(req);
break;
diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h
index 697fbf3bfd..4fb49c48bc 100644
--- a/src/network/networkd-queue.h
+++ b/src/network/networkd-queue.h
@@ -22,6 +22,7 @@ typedef int (*request_after_configure_handler_t)(Request*, void*);
typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType {
+ REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_ADDRESS,
REQUEST_TYPE_ADDRESS_LABEL,
REQUEST_TYPE_BRIDGE_FDB,
diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c
index 1184fbfb43..5abe379b6b 100644
--- a/src/network/networkd-setlink.c
+++ b/src/network/networkd-setlink.c
@@ -464,7 +464,7 @@ static bool link_is_ready_to_call_set_link(Request *req) {
if (FLAGS_SET(link->flags, IFF_UP)) {
/* link must be down when joining to bond master. */
- r = link_down(link, NULL);
+ r = link_down(link);
if (r < 0) {
link_enter_failed(link);
return false;
@@ -711,3 +711,158 @@ int link_configure_mtu(Link *link) {
return link_request_to_set_mtu(link, mtu);
}
+
+static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool check_ready) {
+ int r;
+
+ assert(m);
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 0;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ log_link_message_warning_errno(link, m, r, up ?
+ "Could not bring up interface, ignoring" :
+ "Could not bring down interface, ignoring");
+
+ if (check_ready) {
+ link->activated = true;
+ link_check_ready(link);
+ }
+
+ return 0;
+}
+
+static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ return link_up_or_down_handler_internal(rtnl, m, link, true, true);
+}
+
+static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ return link_up_or_down_handler_internal(rtnl, m, link, false, true);
+}
+
+static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ return link_up_or_down_handler_internal(rtnl, m, link, true, false);
+}
+
+static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ return link_up_or_down_handler_internal(rtnl, m, link, false, false);
+}
+
+static int link_up_or_down(Link *link, bool up, link_netlink_message_handler_t callback) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+ assert(callback);
+
+ log_link_debug(link, "Bringing link %s", up ? "up" : "down");
+
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_rtnl_message_link_set_flags(req, up ? IFF_UP : 0, IFF_UP);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not set link flags: %m");
+
+ r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
+ link_netlink_destroy_callback, link);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
+int link_up(Link *link) {
+ return link_up_or_down(link, true, link_up_handler);
+}
+
+int link_down(Link *link) {
+ return link_up_or_down(link, false, link_down_handler);
+}
+
+static bool link_is_ready_to_activate(Link *link) {
+ assert(link);
+
+ if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return false;
+
+ if (link->set_link_messages > 0)
+ return false;
+
+ return true;
+}
+
+int request_process_activation(Request *req) {
+ Link *link;
+ bool up;
+ int r;
+
+ assert(req);
+ assert(req->link);
+ assert(req->type == REQUEST_TYPE_ACTIVATE_LINK);
+ assert(req->netlink_handler);
+
+ link = req->link;
+ up = PTR_TO_INT(req->userdata);
+
+ if (!link_is_ready_to_activate(link))
+ return 0;
+
+ r = link_up_or_down(link, up, req->netlink_handler);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to bring %s: %m", up ? "up" : "down");
+
+ return 1;
+}
+
+int link_request_to_activate(Link *link) {
+ Request *req;
+ bool up;
+ int r;
+
+ assert(link);
+ assert(link->network);
+
+ switch (link->network->activation_policy) {
+ case ACTIVATION_POLICY_BOUND:
+ /* FIXME: also use request queue to handle the list. */
+ r = link_handle_bound_to_list(link);
+ if (r < 0)
+ return r;
+ _fallthrough_;
+ case ACTIVATION_POLICY_MANUAL:
+ link->activated = true;
+ link_check_ready(link);
+ return 0;
+ case ACTIVATION_POLICY_UP:
+ case ACTIVATION_POLICY_ALWAYS_UP:
+ up = true;
+ break;
+ case ACTIVATION_POLICY_DOWN:
+ case ACTIVATION_POLICY_ALWAYS_DOWN:
+ up = false;
+ break;
+ default:
+ assert_not_reached("invalid activation policy");
+ }
+
+ link->activated = false;
+
+ r = link_queue_request(link, REQUEST_TYPE_ACTIVATE_LINK, NULL, false, NULL,
+ up ? link_activate_up_handler : link_activate_down_handler, &req);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to request to activate link: %m");
+
+ req->userdata = INT_TO_PTR(up);
+
+ log_link_debug(link, "Requested to activate link");
+ return 0;
+}
diff --git a/src/network/networkd-setlink.h b/src/network/networkd-setlink.h
index 7c28fff259..463a2d114f 100644
--- a/src/network/networkd-setlink.h
+++ b/src/network/networkd-setlink.h
@@ -33,3 +33,9 @@ int link_request_to_set_mtu(Link *link, uint32_t mtu);
int link_configure_mtu(Link *link);
int request_process_set_link(Request *req);
+
+int link_up(Link *link);
+int link_down(Link *link);
+
+int request_process_activation(Request *req);
+int link_request_to_activate(Link *link);