#include "ip-protocol-list.h"
#include "netlink-util.h"
#include "networkd-manager.h"
+#include "networkd-queue.h"
+#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-util.h"
#include "parse-util.h"
return -ENOENT;
}
-static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
+static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
RoutingPolicyRule *existing;
bool is_new = false;
assert(m);
assert(in);
- assert(IN_SET(family, AF_INET, AF_INET6));
- assert(in->family == AF_UNSPEC || in->family == family);
+ assert(IN_SET(in->family, AF_INET, AF_INET6));
r = routing_policy_rule_dup(in, &rule);
if (r < 0)
return r;
- rule->family = family;
-
r = routing_policy_rule_get(m, rule, &existing);
if (r == -ENOENT) {
/* Rule does not exist, use a new one. */
return 1;
}
-static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, int family, const char *str, const Link *link, const Manager *m) {
+static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
_cleanup_free_ char *from = NULL, *to = NULL, *table = NULL;
assert(rule);
- assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(IN_SET(rule->family, AF_INET, AF_INET6));
assert(str);
assert(m);
if (!DEBUG_LOGGING)
return;
- (void) in_addr_prefix_to_string(family, &rule->from, rule->from_prefixlen, &from);
- (void) in_addr_prefix_to_string(family, &rule->to, rule->to_prefixlen, &to);
+ (void) in_addr_prefix_to_string(rule->family, &rule->from, rule->from_prefixlen, &from);
+ (void) in_addr_prefix_to_string(rule->family, &rule->to, rule->to_prefixlen, &to);
(void) manager_get_route_table_to_string(m, rule->table, &table);
log_link_debug(link,
return 0;
}
-static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
int r;
assert(m);
+ assert(manager);
+ assert(manager->routing_policy_rule_remove_messages > 0);
+
+ manager->routing_policy_rule_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0)
assert(manager->rtnl);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
- log_routing_policy_rule_debug(rule, rule->family, "Removing", NULL, manager);
+ log_routing_policy_rule_debug(rule, "Removing", NULL, manager);
r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family);
if (r < 0)
if (r < 0)
return r;
- r = sd_netlink_call_async(manager->rtnl, NULL, m,
- routing_policy_rule_remove_handler,
- NULL, NULL, 0, __func__);
+ r = netlink_call_async(manager->rtnl, NULL, m,
+ routing_policy_rule_remove_handler,
+ NULL, manager);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
+ manager->routing_policy_rule_remove_messages++;
+
return 0;
}
static int routing_policy_rule_configure(
const RoutingPolicyRule *rule,
- int family,
Link *link,
link_netlink_message_handler_t callback,
RoutingPolicyRule **ret) {
int r;
assert(rule);
- assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(IN_SET(rule->family, AF_INET, AF_INET6));
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
assert(callback);
- log_routing_policy_rule_debug(rule, family, "Configuring", link, link->manager);
+ log_routing_policy_rule_debug(rule, "Configuring", link, link->manager);
- r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, family);
+ r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
if (r < 0)
return r;
+ r = routing_policy_rule_add(link->manager, rule, ret);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not add rule: %m");
+
r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
- link->routing_policy_rule_messages++;
-
- r = routing_policy_rule_add(link->manager, rule, family, ret);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not add rule: %m");
return r;
}
assert(m);
assert(link);
assert(link->ifname);
- assert(link->routing_policy_rule_messages > 0);
+ assert(link->static_routing_policy_rule_messages > 0);
- link->routing_policy_rule_messages--;
+ link->static_routing_policy_rule_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
return 1;
}
- if (link->routing_policy_rule_messages == 0) {
+ if (link->static_routing_policy_rule_messages == 0) {
log_link_debug(link, "Routing policy rule configured");
- link->routing_policy_rules_configured = true;
+ link->static_routing_policy_rules_configured = true;
link_check_ready(link);
}
return 1;
}
-static int static_routing_policy_rule_configure(const RoutingPolicyRule *rule, Link *link) {
+static int link_request_routing_policy_rule(
+ Link *link,
+ RoutingPolicyRule *rule,
+ bool consume_object,
+ unsigned *message_counter,
+ link_netlink_message_handler_t netlink_handler,
+ Request **ret) {
+
+ assert(link);
+ assert(link->manager);
+ assert(rule);
+
+ log_routing_policy_rule_debug(rule, "Requesting", link, link->manager);
+ return link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, rule, consume_object,
+ message_counter, netlink_handler, ret);
+}
+
+static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
int r;
if (IN_SET(rule->family, AF_INET, AF_INET6))
- return routing_policy_rule_configure(rule, rule->family, link, static_routing_policy_rule_configure_handler, NULL);
+ return link_request_routing_policy_rule(link, rule, false,
+ &link->static_routing_policy_rule_messages,
+ static_routing_policy_rule_configure_handler,
+ NULL);
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
- r = routing_policy_rule_configure(rule, AF_INET, link, static_routing_policy_rule_configure_handler, NULL);
+ _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+
+ r = routing_policy_rule_dup(rule, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->family = AF_INET;
+
+ r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
+ &link->static_routing_policy_rule_messages,
+ static_routing_policy_rule_configure_handler,
+ NULL);
if (r < 0)
return r;
}
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
- r = routing_policy_rule_configure(rule, AF_INET6, link, static_routing_policy_rule_configure_handler, NULL);
+ _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+
+ r = routing_policy_rule_dup(rule, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->family = AF_INET6;
+
+ r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
+ &link->static_routing_policy_rule_messages,
+ static_routing_policy_rule_configure_handler,
+ NULL);
if (r < 0)
return r;
}
return 0;
}
-int link_set_routing_policy_rules(Link *link) {
+int link_request_static_routing_policy_rules(Link *link) {
RoutingPolicyRule *rule;
int r;
assert(link);
assert(link->network);
- if (link->routing_policy_rule_messages != 0) {
- log_link_debug(link, "Routing policy rules are configuring.");
- return 0;
- }
-
- link->routing_policy_rules_configured = false;
+ link->static_routing_policy_rules_configured = false;
HASHMAP_FOREACH(rule, link->network->rules_by_section) {
- r = static_routing_policy_rule_configure(rule, link);
+ r = link_request_static_routing_policy_rule(link, rule);
if (r < 0)
- return log_link_warning_errno(link, r, "Could not set routing policy rule: %m");
+ return log_link_warning_errno(link, r, "Could not request routing policy rule: %m");
}
- if (link->routing_policy_rule_messages == 0)
- link->routing_policy_rules_configured = true;
- else {
- log_link_debug(link, "Setting routing policy rules");
+ if (link->static_routing_policy_rule_messages == 0) {
+ link->static_routing_policy_rules_configured = true;
+ link_check_ready(link);
+ } else {
+ log_link_debug(link, "Requesting routing policy rules");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
+int request_process_routing_policy_rule(Request *req) {
+ RoutingPolicyRule *ret = NULL; /* avoid false maybe-uninitialized warning */
+ int r;
+
+ assert(req);
+ assert(req->link);
+ assert(req->rule);
+ assert(req->type == REQUEST_TYPE_ROUTING_POLICY_RULE);
+
+ if (!link_is_ready_to_configure(req->link, false))
+ return 0;
+
+ if (req->link->manager->routing_policy_rule_remove_messages > 0)
+ return 0;
+
+ r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler, &ret);
+ if (r < 0)
+ return r;
+
+ if (req->after_configure) {
+ r = req->after_configure(req, ret);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+}
+
static const RoutingPolicyRule kernel_rules[] = {
{ .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
{ .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
switch (type) {
case RTM_NEWRULE:
if (rule)
- log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL, m);
+ log_routing_policy_rule_debug(tmp, "Received remembered", NULL, m);
else if (!m->manage_foreign_routes)
- log_routing_policy_rule_debug(tmp, tmp->family, "Ignoring received foreign", NULL, m);
+ log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m);
else {
- log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL, m);
+ log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m);
r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp));
if (r < 0)
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
break;
case RTM_DELRULE:
if (rule) {
- log_routing_policy_rule_debug(tmp, tmp->family, "Forgetting", NULL, m);
+ log_routing_policy_rule_debug(tmp, "Forgetting", NULL, m);
routing_policy_rule_free(rule);
} else
- log_routing_policy_rule_debug(tmp, tmp->family, "Kernel removed unknown", NULL, m);
+ log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
break;
default: