static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
assert(netdev);
- assert(link);
if (netdev->state != NETDEV_STATE_LOADING)
return false;
- if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
- return false;
+ if (link) {
+ if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return false;
- if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
- link->state != LINK_STATE_CONFIGURED)
- return false;
+ if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
+ link->state != LINK_STATE_CONFIGURED)
+ return false;
- if (link->set_link_messages > 0)
- return false;
+ if (link->set_link_messages > 0)
+ return false;
+ }
if (NETDEV_VTABLE(netdev)->is_ready_to_create)
return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
return 0;
}
+int request_process_independent_netdev(Request *req) {
+ int r;
+
+ assert(req);
+ assert(req->type == REQUEST_TYPE_NETDEV_INDEPENDENT);
+ assert(req->netdev);
+
+ r = netdev_is_ready_to_create(req->netdev, NULL);
+ if (r <= 0)
+ return r;
+
+ r = netdev_create(req->netdev, NULL, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int netdev_request(NetDev *netdev) {
+ int r;
+
+ assert(netdev);
+
+ if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT) &&
+ !netdev_is_stacked_and_independent(netdev))
+ return 0;
+
+ r = netdev_is_ready_to_create(netdev, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ /* If the netdev has no dependency, then create it now. */
+ return netdev_create(netdev, NULL, NULL);
+
+ /* Otherwise, wait for the dependencies being resolved. */
+ return netdev_queue_request(netdev, NULL);
+}
+
int netdev_load_one(Manager *manager, const char *filename) {
_cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
const char *dropin_dirname;
log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
- if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {
- r = netdev_create(netdev, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- if (netdev_is_stacked_and_independent(netdev)) {
- r = netdev_create(netdev, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- netdev = NULL;
+ r = netdev_request(netdev);
+ if (r < 0)
+ return log_netdev_warning_errno(netdev, r, "Failed to request to create: %m");
+ TAKE_PTR(netdev);
return 0;
}
const struct hw_addr_data *hw_addr, struct hw_addr_data *ret);
int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
+int request_process_independent_netdev(Request *req);
int request_process_stacked_netdev(Request *req);
int link_request_stacked_netdev(Link *link, NetDev *netdev);
Tunnel *t;
assert(netdev);
- assert(link);
t = TUNNEL(netdev);
assert(t);
+ if (t->independent)
+ return true;
+
return tunnel_get_local_address(t, link, NULL) >= 0;
}
VxLan *v;
assert(netdev);
- assert(link);
v = VXLAN(netdev);
assert(v);
+ if (v->independent)
+ return true;
+
return vxlan_get_local_address(v, link, NULL, NULL) >= 0;
}
case REQUEST_TYPE_NEIGHBOR:
neighbor_free(object);
break;
+ case REQUEST_TYPE_NETDEV_INDEPENDENT:
case REQUEST_TYPE_NETDEV_STACKED:
netdev_unref(object);
break;
static void request_hash_func(const Request *req, struct siphash *state) {
assert(req);
- assert(req->link);
assert(state);
- siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
+ siphash24_compress_boolean(req->link, state);
+ if (req->link)
+ siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
+
siphash24_compress(&req->type, sizeof(req->type), state);
switch (req->type) {
case REQUEST_TYPE_ADDRESS_LABEL:
case REQUEST_TYPE_BRIDGE_FDB:
case REQUEST_TYPE_BRIDGE_MDB:
+ case REQUEST_TYPE_NETDEV_INDEPENDENT:
case REQUEST_TYPE_NETDEV_STACKED:
/* TODO: Currently, these types do not have any specific hash and compare functions.
* Fortunately, all these objects are 'static', thus we can use the trivial functions. */
assert(a);
assert(b);
- assert(a->link);
- assert(b->link);
- r = CMP(a->link->ifindex, b->link->ifindex);
+ r = CMP(!!a->link, !!b->link);
if (r != 0)
return r;
+ if (a->link) {
+ r = CMP(a->link->ifindex, b->link->ifindex);
+ if (r != 0)
+ return r;
+ }
+
r = CMP(a->type, b->type);
if (r != 0)
return r;
case REQUEST_TYPE_ADDRESS_LABEL:
case REQUEST_TYPE_BRIDGE_FDB:
case REQUEST_TYPE_BRIDGE_MDB:
+ case REQUEST_TYPE_NETDEV_INDEPENDENT:
case REQUEST_TYPE_NETDEV_STACKED:
return trivial_compare_func(a->object, b->object);
case REQUEST_TYPE_DHCP_SERVER:
request_compare_func,
request_free);
+int netdev_queue_request(
+ NetDev *netdev,
+ Request **ret) {
+
+ _cleanup_(request_freep) Request *req = NULL;
+ Request *existing;
+ int r;
+
+ assert(netdev);
+ assert(netdev->manager);
+
+ req = new(Request, 1);
+ if (!req)
+ return -ENOMEM;
+
+ *req = (Request) {
+ .netdev = netdev_ref(netdev),
+ .type = REQUEST_TYPE_NETDEV_INDEPENDENT,
+ .consume_object = true,
+ };
+
+ existing = ordered_set_get(netdev->manager->request_queue, req);
+ if (existing) {
+ /* To prevent from removing the existing request. */
+ req->netdev = netdev_unref(req->netdev);
+
+ if (ret)
+ *ret = existing;
+ return 0;
+ }
+
+ r = ordered_set_ensure_put(&netdev->manager->request_queue, &request_hash_ops, req);
+ if (r < 0)
+ return r;
+
+ if (ret)
+ *ret = req;
+
+ TAKE_PTR(req);
+ return 1;
+}
+
int link_queue_request(
Link *link,
RequestType type,
case REQUEST_TYPE_NEIGHBOR:
r = request_process_neighbor(req);
break;
+ case REQUEST_TYPE_NETDEV_INDEPENDENT:
+ r = request_process_independent_netdev(req);
+ break;
case REQUEST_TYPE_NETDEV_STACKED:
r = request_process_stacked_netdev(req);
break;
default:
return -EINVAL;
}
- if (r < 0)
- link_enter_failed(req->link);
- if (r > 0) {
+ if (r < 0) {
+ if (req->link)
+ link_enter_failed(req->link);
+ } else if (r > 0) {
ordered_set_remove(manager->request_queue, req);
request_free(req);
processed = true;
REQUEST_TYPE_IPV6_PROXY_NDP,
REQUEST_TYPE_NDISC,
REQUEST_TYPE_NEIGHBOR,
+ REQUEST_TYPE_NETDEV_INDEPENDENT,
REQUEST_TYPE_NETDEV_STACKED,
REQUEST_TYPE_NEXTHOP,
REQUEST_TYPE_RADV,
void request_drop(Request *req);
+int netdev_queue_request(
+ NetDev *netdev,
+ Request **ret);
+
int link_queue_request(
Link *link,
RequestType type,