dhcp6_pd_route_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 prefix route: %m");
+ if (r == 0)
+ return 0;
req->after_configure = dhcp6_pd_after_route_configure;
dhcp6_pd_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 delegated prefix address: %m");
+ if (r == 0)
+ return 0;
req->after_configure = dhcp6_pd_after_address_configure;
if (r < 0)
return log_link_error_errno(link, r, "Failed to request unreachable route for DHCPv6 delegated subnet %s: %m",
strna(buf));
+ if (r == 0)
+ return 0;
req->after_configure = dhcp6_after_route_configure;
dhcp6_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 address %s: %m", strna(buffer));
+ if (r == 0)
+ return 0;
req->after_configure = dhcp6_after_address_configure;
}
}
-Request *request_free(Request *req) {
+static Request *request_free(Request *req) {
if (!req)
return NULL;
+ if (req->link && req->link->manager)
+ /* To prevent from triggering assertions in hash functions, remove this request before
+ * freeing object below. */
+ ordered_set_remove(req->link->manager->request_queue, req);
if (req->on_free)
+ /* on_free() may use object. So, let's call this earlier. */
req->on_free(req);
if (req->consume_object)
request_free_object(req->type, req->object);
- if (req->link && req->link->manager)
- ordered_set_remove(req->link->manager->request_queue, req);
link_unref(req->link);
return mfree(req);
request_free(req);
}
+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(&req->type, sizeof(req->type), state);
+
+ switch(req->type) {
+ case REQUEST_TYPE_ADDRESS:
+ address_hash_func(req->address, state);
+ break;
+ case REQUEST_TYPE_ADDRESS_LABEL:
+ case REQUEST_TYPE_BRIDGE_FDB:
+ case REQUEST_TYPE_BRIDGE_MDB:
+ /* 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. */
+ trivial_hash_func(req->object, state);
+ break;
+ case REQUEST_TYPE_DHCP_SERVER:
+ /* This type does not have object. */
+ break;
+ case REQUEST_TYPE_IPV6_PROXY_NDP:
+ in6_addr_hash_func(req->ipv6_proxy_ndp, state);
+ break;
+ case REQUEST_TYPE_NEIGHBOR:
+ neighbor_hash_func(req->neighbor, state);
+ break;
+ case REQUEST_TYPE_NEXTHOP:
+ nexthop_hash_func(req->nexthop, state);
+ break;
+ case REQUEST_TYPE_ROUTE:
+ route_hash_func(req->route, state);
+ break;
+ case REQUEST_TYPE_ROUTING_POLICY_RULE:
+ routing_policy_rule_hash_func(req->rule, state);
+ break;
+ default:
+ assert_not_reached("invalid request type.");
+ }
+}
+
+static int request_compare_func(const struct Request *a, const struct Request *b) {
+ int r;
+
+ assert(a);
+ assert(b);
+ assert(a->link);
+ assert(b->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;
+
+ switch (a->type) {
+ case REQUEST_TYPE_ADDRESS:
+ return address_compare_func(a->address, b->address);
+ case REQUEST_TYPE_ADDRESS_LABEL:
+ case REQUEST_TYPE_BRIDGE_FDB:
+ case REQUEST_TYPE_BRIDGE_MDB:
+ return trivial_compare_func(a->object, b->object);
+ case REQUEST_TYPE_DHCP_SERVER:
+ return 0;
+ case REQUEST_TYPE_IPV6_PROXY_NDP:
+ return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
+ case REQUEST_TYPE_NEIGHBOR:
+ return neighbor_compare_func(a->neighbor, b->neighbor);
+ case REQUEST_TYPE_NEXTHOP:
+ return nexthop_compare_func(a->nexthop, b->nexthop);
+ case REQUEST_TYPE_ROUTE:
+ return route_compare_func(a->route, b->route);
+ case REQUEST_TYPE_ROUTING_POLICY_RULE:
+ return routing_policy_rule_compare_func(a->rule, b->rule);
+ default:
+ assert_not_reached("invalid request type.");
+ }
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ request_hash_ops,
+ Request,
+ request_hash_func,
+ request_compare_func,
+ request_free);
+
int link_queue_request(
Link *link,
RequestType type,
}
*req = (Request) {
- .link = link,
+ .link = link_ref(link),
.type = type,
.object = object,
.consume_object = consume_object,
.netlink_handler = netlink_handler,
};
- link_ref(link);
+ r = ordered_set_ensure_put(&link->manager->request_queue, &request_hash_ops, req);
+ if (r < 0) {
+ /* To prevent from removing duplicated request. */
+ req->link = link_unref(req->link);
- r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req);
- if (r < 0)
+ if (r == -EEXIST) {
+ if (ret)
+ *ret = NULL;
+ return 0;
+ }
return r;
+ }
if (req->message_counter)
(*req->message_counter)++;
*ret = req;
TAKE_PTR(req);
- return 0;
+ return 1;
}
int manager_process_requests(sd_event_source *s, void *userdata) {