Merge pull request #34049 from yuwata/network-routing-policy-rule
network: further rework for routing policy rule
This commit is contained in:
+16
-2
@@ -1728,6 +1728,18 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>GoTo=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the target priority used by <literal>goto</literal> type of rule. Takes an integer
|
||||
in the range 1…4294967295. This must be larger than the priority of this rule specified in
|
||||
<varname>Priority=</varname>. When specified, <varname>Type=goto</varname> is implied. This is
|
||||
mandatory when <varname>Type=goto</varname>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>IncomingInterface=</varname></term>
|
||||
<listitem>
|
||||
@@ -1853,8 +1865,10 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting>
|
||||
<term><varname>Type=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies Routing Policy Database (RPDB) rule type. Takes one of
|
||||
<literal>blackhole</literal>, <literal>unreachable</literal> or <literal>prohibit</literal>.
|
||||
</para>
|
||||
<literal>table</literal>, <literal>goto</literal>, <literal>nop</literal>,
|
||||
<literal>blackhole</literal>, <literal>unreachable</literal>, or <literal>prohibit</literal>.
|
||||
When <literal>goto</literal>, the target priority must be specified in <varname>GoTo=</varname>.
|
||||
Defaults to <literal>table</literal>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v248"/>
|
||||
</listitem>
|
||||
|
||||
@@ -928,6 +928,34 @@ int sd_netlink_message_read_u32(sd_netlink_message *m, uint16_t attr_type, uint3
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_read_u64(sd_netlink_message *m, uint16_t attr_type, uint64_t *ret) {
|
||||
void *attr_data;
|
||||
bool net_byteorder;
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
|
||||
r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if ((size_t) r < sizeof(uint64_t))
|
||||
return -EIO;
|
||||
|
||||
if (ret) {
|
||||
if (net_byteorder)
|
||||
*ret = be64toh(*(uint64_t *) attr_data);
|
||||
else
|
||||
*ret = *(uint64_t *) attr_data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_read_ether_addr(sd_netlink_message *m, uint16_t attr_type, struct ether_addr *data) {
|
||||
void *attr_data;
|
||||
int r;
|
||||
|
||||
@@ -308,7 +308,7 @@ static int routing_policy_rule_append_json(RoutingPolicyRule *rule, sd_json_vari
|
||||
SD_JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("TOS", rule->tos),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("Type", rule->type),
|
||||
SD_JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule->type)),
|
||||
SD_JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_to_string(rule->type)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule->ipproto),
|
||||
SD_JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule->ipproto)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("Priority", rule->priority),
|
||||
|
||||
@@ -178,6 +178,7 @@ Neighbor.LinkLayerAddress, config_parse_neighbor_lladdr,
|
||||
Neighbor.MACAddress, config_parse_neighbor_lladdr, 0, 0 /* deprecated */
|
||||
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule_tos, 0, 0
|
||||
RoutingPolicyRule.Priority, config_parse_routing_policy_rule_priority, 0, 0
|
||||
RoutingPolicyRule.GoTo, config_parse_routing_policy_rule_goto, 0, 0
|
||||
RoutingPolicyRule.Table, config_parse_routing_policy_rule_table, 0, 0
|
||||
RoutingPolicyRule.FirewallMark, config_parse_routing_policy_rule_fwmark_mask, 0, 0
|
||||
RoutingPolicyRule.From, config_parse_routing_policy_rule_prefix, 0, 0
|
||||
|
||||
@@ -58,7 +58,11 @@ static void request_hash_func(const Request *req, struct siphash *state) {
|
||||
|
||||
siphash24_compress_typesafe(req->type, state);
|
||||
|
||||
if (!IN_SET(req->type, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_ROUTE)) {
|
||||
if (!IN_SET(req->type,
|
||||
REQUEST_TYPE_NEXTHOP,
|
||||
REQUEST_TYPE_ROUTE,
|
||||
REQUEST_TYPE_ROUTING_POLICY_RULE)) {
|
||||
|
||||
siphash24_compress_boolean(req->link, state);
|
||||
if (req->link)
|
||||
siphash24_compress_typesafe(req->link->ifindex, state);
|
||||
@@ -81,7 +85,11 @@ static int request_compare_func(const struct Request *a, const struct Request *b
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (!IN_SET(a->type, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_ROUTE)) {
|
||||
if (!IN_SET(a->type,
|
||||
REQUEST_TYPE_NEXTHOP,
|
||||
REQUEST_TYPE_ROUTE,
|
||||
REQUEST_TYPE_ROUTING_POLICY_RULE)) {
|
||||
|
||||
r = CMP(!!a->link, !!b->link);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
@@ -25,12 +25,6 @@
|
||||
#include "user-util.h"
|
||||
|
||||
static const char *const fr_act_type_table[__FR_ACT_MAX] = {
|
||||
[FR_ACT_BLACKHOLE] = "blackhole",
|
||||
[FR_ACT_UNREACHABLE] = "unreachable",
|
||||
[FR_ACT_PROHIBIT] = "prohibit",
|
||||
};
|
||||
|
||||
static const char *const fr_act_type_full_table[__FR_ACT_MAX] = {
|
||||
[FR_ACT_TO_TBL] = "table",
|
||||
[FR_ACT_GOTO] = "goto",
|
||||
[FR_ACT_NOP] = "nop",
|
||||
@@ -40,8 +34,7 @@ static const char *const fr_act_type_full_table[__FR_ACT_MAX] = {
|
||||
};
|
||||
|
||||
assert_cc(__FR_ACT_MAX <= UINT8_MAX);
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fr_act_type, int);
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(fr_act_type_full, int);
|
||||
DEFINE_STRING_TABLE_LOOKUP(fr_act_type, int);
|
||||
|
||||
static RoutingPolicyRule* routing_policy_rule_detach_impl(RoutingPolicyRule *rule) {
|
||||
assert(rule);
|
||||
@@ -162,7 +155,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRule **ret) {
|
||||
static int routing_policy_rule_dup(const RoutingPolicyRule *src, int family, RoutingPolicyRule **ret) {
|
||||
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *dest = NULL;
|
||||
|
||||
assert(src);
|
||||
@@ -179,6 +172,9 @@ static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRu
|
||||
dest->section = NULL;
|
||||
dest->iif = dest->oif = NULL;
|
||||
|
||||
/* Set family. */
|
||||
dest->family = family;
|
||||
|
||||
if (src->iif) {
|
||||
dest->iif = strdup(src->iif);
|
||||
if (!dest->iif)
|
||||
@@ -209,7 +205,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
|
||||
siphash24_compress_typesafe(rule->suppress_ifgroup, state);
|
||||
siphash24_compress_typesafe(rule->suppress_prefixlen, state);
|
||||
siphash24_compress_typesafe(rule->fwmask, state);
|
||||
/* FRA_TUN_ID */
|
||||
siphash24_compress_typesafe(rule->tunnel_id, state);
|
||||
/* fr_net (network namespace) */
|
||||
siphash24_compress_typesafe(rule->l3mdev, state);
|
||||
siphash24_compress_typesafe(rule->uid_range, state);
|
||||
@@ -222,20 +218,22 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
|
||||
siphash24_compress_typesafe(rule->from_prefixlen, state);
|
||||
siphash24_compress_typesafe(rule->to_prefixlen, state);
|
||||
siphash24_compress_typesafe(rule->tos, state);
|
||||
/* FRA_FLOW (IPv4 only) */
|
||||
siphash24_compress_typesafe(rule->realms, state);
|
||||
in_addr_hash_func(&rule->from, rule->family, state);
|
||||
in_addr_hash_func(&rule->to, rule->family, state);
|
||||
}
|
||||
|
||||
static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
|
||||
static int routing_policy_rule_compare_func_full(const RoutingPolicyRule *a, const RoutingPolicyRule *b, bool all) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = CMP(a->family, b->family);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (all) {
|
||||
r = CMP(a->family, b->family);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = CMP(a->type, b->type);
|
||||
if (r != 0)
|
||||
@@ -245,9 +243,11 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->priority, b->priority);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (all) {
|
||||
r = CMP(a->priority, b->priority);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = strcmp_ptr(a->iif, b->iif);
|
||||
if (r != 0)
|
||||
@@ -273,6 +273,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->tunnel_id, b->tunnel_id);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->l3mdev, b->l3mdev);
|
||||
if (r != 0)
|
||||
return r;
|
||||
@@ -309,62 +313,126 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
|
||||
r = CMP(a->realms, b->realms);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (all) {
|
||||
r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool routing_policy_rule_equal(const RoutingPolicyRule *rule1, const RoutingPolicyRule *rule2) {
|
||||
if (rule1 == rule2)
|
||||
return true;
|
||||
|
||||
if (!rule1 || !rule2)
|
||||
return false;
|
||||
|
||||
return routing_policy_rule_compare_func(rule1, rule2) == 0;
|
||||
static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
|
||||
return routing_policy_rule_compare_func_full(a, b, /* all = */ true);
|
||||
}
|
||||
|
||||
static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
|
||||
static bool routing_policy_rule_equal(const RoutingPolicyRule *a, const RoutingPolicyRule *b, int family, uint32_t priority) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
if (a->family != AF_UNSPEC && a->family != family)
|
||||
return false;
|
||||
if (b->family != AF_UNSPEC && b->family != family)
|
||||
return false;
|
||||
|
||||
if (a->priority_set && a->priority != priority)
|
||||
return false;
|
||||
if (b->priority_set && b->priority != priority)
|
||||
return false;
|
||||
|
||||
return routing_policy_rule_compare_func_full(a, b, /* all = */ false) == 0;
|
||||
}
|
||||
|
||||
static bool routing_policy_rule_can_update(const RoutingPolicyRule *existing, const RoutingPolicyRule *requesting, int family) {
|
||||
assert(existing);
|
||||
assert(requesting);
|
||||
|
||||
if (!routing_policy_rule_equal(existing, requesting, family, existing->priority))
|
||||
return false;
|
||||
|
||||
/* These flags cannot be updated. */
|
||||
if ((existing->flags ^ requesting->flags) & (FIB_RULE_PERMANENT|FIB_RULE_INVERT))
|
||||
return false;
|
||||
|
||||
/* GOTO target cannot be updated. */
|
||||
if (existing->type == FR_ACT_GOTO && existing->priority_goto != requesting->priority_goto)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
|
||||
RoutingPolicyRule *rule;
|
||||
|
||||
assert(m);
|
||||
assert(in);
|
||||
assert(in->family == AF_UNSPEC || in->family == family);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
if (in->priority_set && in->family != AF_UNSPEC) {
|
||||
rule = set_get(m->rules, in);
|
||||
if (!rule)
|
||||
return -ENOENT;
|
||||
|
||||
rule = set_get(m->rules, in);
|
||||
if (rule) {
|
||||
if (ret)
|
||||
*ret = rule;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in->priority_set)
|
||||
return -ENOENT;
|
||||
|
||||
/* Also find rules configured without priority. */
|
||||
SET_FOREACH(rule, m->rules) {
|
||||
uint32_t priority;
|
||||
bool found;
|
||||
|
||||
if (rule->priority_set)
|
||||
/* The rule is configured with priority. */
|
||||
continue;
|
||||
|
||||
priority = rule->priority;
|
||||
rule->priority = 0;
|
||||
found = routing_policy_rule_equal(rule, in);
|
||||
rule->priority = priority;
|
||||
|
||||
if (found) {
|
||||
SET_FOREACH(rule, m->rules)
|
||||
if (routing_policy_rule_equal(in, rule, family, rule->priority)) {
|
||||
if (ret)
|
||||
*ret = rule;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_get_request(Manager *m, const RoutingPolicyRule *in, int family, Request **ret) {
|
||||
Request *req;
|
||||
|
||||
assert(m);
|
||||
assert(in);
|
||||
assert(in->family == AF_UNSPEC || in->family == family);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
if (in->priority_set && in->family != AF_UNSPEC) {
|
||||
req = ordered_set_get(
|
||||
m->request_queue,
|
||||
&(Request) {
|
||||
.type = REQUEST_TYPE_ROUTING_POLICY_RULE,
|
||||
.userdata = (void*) in,
|
||||
.hash_func = (hash_func_t) routing_policy_rule_hash_func,
|
||||
.compare_func = (compare_func_t) routing_policy_rule_compare_func,
|
||||
});
|
||||
if (!req)
|
||||
return -ENOENT;
|
||||
|
||||
if (ret)
|
||||
*ret = req;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ORDERED_SET_FOREACH(req, m->request_queue) {
|
||||
|
||||
if (req->type != REQUEST_TYPE_ROUTING_POLICY_RULE)
|
||||
continue;
|
||||
|
||||
RoutingPolicyRule *rule = ASSERT_PTR(req->userdata);
|
||||
if (routing_policy_rule_equal(in, rule, family, rule->priority)) {
|
||||
if (ret)
|
||||
*ret = req;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
@@ -416,6 +484,21 @@ static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyR
|
||||
return r;
|
||||
}
|
||||
|
||||
Request *req;
|
||||
ORDERED_SET_FOREACH(req, manager->request_queue) {
|
||||
if (req->type != REQUEST_TYPE_ROUTING_POLICY_RULE)
|
||||
continue;
|
||||
|
||||
tmp = ASSERT_PTR(req->userdata);
|
||||
if (tmp->family != rule->family)
|
||||
continue;
|
||||
if (tmp->priority == 0 || tmp->priority > 32765)
|
||||
continue;
|
||||
r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(network, manager->networks)
|
||||
HASHMAP_FOREACH(tmp, network->rules_by_section) {
|
||||
if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
|
||||
@@ -429,11 +512,13 @@ static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyR
|
||||
return r;
|
||||
}
|
||||
|
||||
for (priority = 32765; priority > 0; priority--)
|
||||
/* priority must be smaller than goto target */
|
||||
for (priority = rule->type == FR_ACT_GOTO ? rule->priority_goto - 1 : 32765; priority > 0; priority--)
|
||||
if (!set_contains(priorities, UINT32_TO_PTR(priority)))
|
||||
break;
|
||||
|
||||
rule->priority = priority;
|
||||
rule->priority_set = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -584,33 +669,76 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (rule->type == FR_ACT_GOTO) {
|
||||
r = sd_netlink_message_append_u32(m, FRA_GOTO, rule->priority_goto);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (rule->realms > 0) {
|
||||
r = sd_netlink_message_append_u32(m, FRA_FLOW, rule->realms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (rule->tunnel_id > 0) {
|
||||
r = sd_netlink_message_append_u64(m, FRA_TUN_ID, htobe64(rule->tunnel_id));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
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, RemoveRequest *rreq) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(rreq);
|
||||
|
||||
Manager *manager = ASSERT_PTR(rreq->manager);
|
||||
RoutingPolicyRule *rule = ASSERT_PTR(rreq->userdata);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_message_warning_errno(m, r, "Could not drop routing policy rule");
|
||||
if (r < 0) {
|
||||
log_message_full_errno(m,
|
||||
(r == -ENOENT || !rule->manager) ? LOG_DEBUG : LOG_WARNING,
|
||||
r, "Could not drop routing policy rule, ignoring");
|
||||
|
||||
if (rule->manager) {
|
||||
/* If the rule cannot be removed, then assume the rule is already removed. */
|
||||
log_routing_policy_rule_debug(rule, "Forgetting", NULL, manager);
|
||||
|
||||
Request *req;
|
||||
if (routing_policy_rule_get_request(manager, rule, rule->family, &req) >= 0)
|
||||
routing_policy_rule_enter_removed(req->userdata);
|
||||
|
||||
routing_policy_rule_detach(rule);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_remove(RoutingPolicyRule *rule) {
|
||||
static int routing_policy_rule_remove(RoutingPolicyRule *rule, Manager *manager) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(rule);
|
||||
assert(rule->manager);
|
||||
assert(rule->manager->rtnl);
|
||||
assert(IN_SET(rule->family, AF_INET, AF_INET6));
|
||||
assert(manager);
|
||||
assert(manager->rtnl);
|
||||
|
||||
log_routing_policy_rule_debug(rule, "Removing", NULL, rule->manager);
|
||||
/* If the rule is remembered, then use the remembered object. */
|
||||
(void) routing_policy_rule_get(manager, rule, rule->family, &rule);
|
||||
|
||||
r = sd_rtnl_message_new_routing_policy_rule(rule->manager->rtnl, &m, RTM_DELRULE, rule->family);
|
||||
/* We cannot remove rules with the permanent flag. */
|
||||
if (FLAGS_SET(rule->flags, FIB_RULE_PERMANENT))
|
||||
return 0;
|
||||
|
||||
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)
|
||||
return log_warning_errno(r, "Could not allocate netlink message: %m");
|
||||
|
||||
@@ -618,11 +746,10 @@ static int routing_policy_rule_remove(RoutingPolicyRule *rule) {
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Could not create netlink message: %m");
|
||||
|
||||
r = netlink_call_async(rule->manager->rtnl, NULL, m,
|
||||
routing_policy_rule_remove_handler,
|
||||
NULL, NULL);
|
||||
r = manager_remove_request_add(manager, rule, routing_policy_rule,
|
||||
manager->rtnl, m, routing_policy_rule_remove_handler);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Could not send netlink message: %m");
|
||||
return log_warning_errno(r, "Could not queue rtnetlink message: %m");
|
||||
|
||||
routing_policy_rule_enter_removing(rule);
|
||||
return 0;
|
||||
@@ -653,6 +780,23 @@ static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, Re
|
||||
return request_call_netlink_async(link->manager->rtnl, m, req);
|
||||
}
|
||||
|
||||
static void manager_unmark_routing_policy_rule(Manager *m, const RoutingPolicyRule *rule, int family) {
|
||||
RoutingPolicyRule *existing;
|
||||
|
||||
assert(m);
|
||||
assert(rule);
|
||||
assert(rule->family == AF_UNSPEC || rule->family == family);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
if (routing_policy_rule_get(m, rule, family, &existing) < 0)
|
||||
return;
|
||||
|
||||
if (!routing_policy_rule_can_update(existing, rule, rule->family))
|
||||
return;
|
||||
|
||||
routing_policy_rule_unmark(existing);
|
||||
}
|
||||
|
||||
static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Link *except) {
|
||||
RoutingPolicyRule *rule;
|
||||
Link *link;
|
||||
@@ -685,22 +829,12 @@ static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Li
|
||||
continue;
|
||||
|
||||
HASHMAP_FOREACH(rule, link->network->rules_by_section) {
|
||||
RoutingPolicyRule *existing;
|
||||
|
||||
if (IN_SET(rule->family, AF_INET, AF_INET6)) {
|
||||
if (routing_policy_rule_get(m, rule, &existing) >= 0)
|
||||
routing_policy_rule_unmark(existing);
|
||||
} else {
|
||||
/* The case Family=both. */
|
||||
rule->family = AF_INET;
|
||||
if (routing_policy_rule_get(m, rule, &existing) >= 0)
|
||||
routing_policy_rule_unmark(existing);
|
||||
|
||||
rule->family = AF_INET6;
|
||||
if (routing_policy_rule_get(m, rule, &existing) >= 0)
|
||||
routing_policy_rule_unmark(existing);
|
||||
|
||||
rule->family = AF_UNSPEC;
|
||||
if (IN_SET(rule->family, AF_INET, AF_INET6))
|
||||
manager_unmark_routing_policy_rule(m, rule, rule->family);
|
||||
else {
|
||||
assert(rule->address_family == ADDRESS_FAMILY_YES);
|
||||
manager_unmark_routing_policy_rule(m, rule, AF_INET);
|
||||
manager_unmark_routing_policy_rule(m, rule, AF_INET6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -718,7 +852,7 @@ int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const L
|
||||
if (!routing_policy_rule_is_marked(rule))
|
||||
continue;
|
||||
|
||||
RET_GATHER(r, routing_policy_rule_remove(rule));
|
||||
RET_GATHER(r, routing_policy_rule_remove(rule, m));
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -741,10 +875,12 @@ void link_foreignize_routing_policy_rules(Link *link) {
|
||||
}
|
||||
|
||||
static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) {
|
||||
RoutingPolicyRule *existing;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(rule);
|
||||
|
||||
if (!link_is_ready_to_configure(link, false))
|
||||
@@ -755,6 +891,9 @@ static int routing_policy_rule_process_request(Request *req, Link *link, Routing
|
||||
return log_link_warning_errno(link, r, "Failed to configure routing policy rule: %m");
|
||||
|
||||
routing_policy_rule_enter_configuring(rule);
|
||||
if (routing_policy_rule_get(link->manager, rule, rule->family, &existing) >= 0)
|
||||
routing_policy_rule_enter_configuring(existing);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -769,16 +908,24 @@ static int static_routing_policy_rule_configure_handler(
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(rule);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
if (r == -EEXIST) {
|
||||
RoutingPolicyRule *existing;
|
||||
|
||||
if (routing_policy_rule_get(link->manager, rule, rule->family, &existing) >= 0) {
|
||||
existing->source = rule->source;
|
||||
routing_policy_rule_enter_configured(existing);
|
||||
}
|
||||
} else if (r < 0) {
|
||||
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (link->static_routing_policy_rule_messages == 0) {
|
||||
log_link_debug(link, "Routing policy rule configured");
|
||||
log_link_debug(link, "Routing policy rule configured.");
|
||||
link->static_routing_policy_rules_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
@@ -786,37 +933,44 @@ static int static_routing_policy_rule_configure_handler(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_request_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
|
||||
RoutingPolicyRule *existing;
|
||||
static int link_request_routing_policy_rule(Link *link, const RoutingPolicyRule *rule, int family) {
|
||||
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
|
||||
RoutingPolicyRule *existing = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(rule);
|
||||
assert(rule->source != NETWORK_CONFIG_SOURCE_FOREIGN);
|
||||
assert(rule->family == AF_UNSPEC || rule->family == family);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
if (routing_policy_rule_get(link->manager, rule, &existing) < 0) {
|
||||
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
|
||||
if (routing_policy_rule_get_request(link->manager, rule, family, NULL) >= 0)
|
||||
return 0; /* already requested, skipping. */
|
||||
|
||||
r = routing_policy_rule_dup(rule, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = routing_policy_rule_dup(rule, family, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (routing_policy_rule_get(link->manager, tmp, family, &existing) < 0) {
|
||||
r = routing_policy_rule_acquire_priority(link->manager, tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
/* Copy priority from existing rule. */
|
||||
if (!tmp->priority_set) {
|
||||
tmp->priority_set = true;
|
||||
tmp->priority = existing->priority;
|
||||
}
|
||||
|
||||
r = routing_policy_rule_attach(link->manager, tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* Copy state for logging below. */
|
||||
tmp->state = existing->state;
|
||||
}
|
||||
|
||||
existing = tmp;
|
||||
} else
|
||||
existing->source = rule->source;
|
||||
|
||||
log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
|
||||
log_routing_policy_rule_debug(tmp, "Requesting", link, link->manager);
|
||||
r = link_queue_request_safe(link, REQUEST_TYPE_ROUTING_POLICY_RULE,
|
||||
existing, NULL,
|
||||
tmp,
|
||||
routing_policy_rule_unref,
|
||||
routing_policy_rule_hash_func,
|
||||
routing_policy_rule_compare_func,
|
||||
routing_policy_rule_process_request,
|
||||
@@ -826,27 +980,31 @@ static int link_request_routing_policy_rule(Link *link, RoutingPolicyRule *rule)
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
routing_policy_rule_enter_requesting(existing);
|
||||
routing_policy_rule_enter_requesting(tmp);
|
||||
if (existing)
|
||||
routing_policy_rule_enter_requesting(existing);
|
||||
|
||||
TAKE_PTR(tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
|
||||
static int link_request_static_routing_policy_rule(Link *link, const RoutingPolicyRule *rule) {
|
||||
int r;
|
||||
|
||||
if (IN_SET(rule->family, AF_INET, AF_INET6))
|
||||
return link_request_routing_policy_rule(link, rule);
|
||||
return link_request_routing_policy_rule(link, rule, rule->family);
|
||||
|
||||
rule->family = AF_INET;
|
||||
r = link_request_routing_policy_rule(link, rule);
|
||||
if (r < 0) {
|
||||
rule->family = AF_UNSPEC;
|
||||
assert(rule->address_family == ADDRESS_FAMILY_YES);
|
||||
|
||||
r = link_request_routing_policy_rule(link, rule, AF_INET);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
rule->family = AF_INET6;
|
||||
r = link_request_routing_policy_rule(link, rule);
|
||||
rule->family = AF_UNSPEC;
|
||||
return r;
|
||||
r = link_request_routing_policy_rule(link, rule, AF_INET6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_request_static_routing_policy_rules(Link *link) {
|
||||
@@ -868,7 +1026,7 @@ int link_request_static_routing_policy_rules(Link *link) {
|
||||
link->static_routing_policy_rules_configured = true;
|
||||
link_check_ready(link);
|
||||
} else {
|
||||
log_link_debug(link, "Requesting routing policy rules");
|
||||
log_link_debug(link, "Requesting routing policy rules.");
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
}
|
||||
|
||||
@@ -888,8 +1046,8 @@ static const RoutingPolicyRule kernel_rules[] = {
|
||||
static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) {
|
||||
assert(rule);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++)
|
||||
if (routing_policy_rule_equal(rule, &kernel_rules[i]))
|
||||
FOREACH_ELEMENT(i, kernel_rules)
|
||||
if (routing_policy_rule_equal(rule, i, i->family, i->priority))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -897,8 +1055,9 @@ static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *ru
|
||||
|
||||
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
|
||||
bool adjust_protocol = false, is_new = false;
|
||||
RoutingPolicyRule *rule = NULL;
|
||||
bool adjust_protocol = false;
|
||||
Request *req = NULL;
|
||||
uint16_t type;
|
||||
int r;
|
||||
|
||||
@@ -961,12 +1120,6 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &tmp->flags);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
|
||||
@@ -1079,47 +1232,81 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
|
||||
if (r >= 0)
|
||||
tmp->suppress_ifgroup = (int32_t) suppress_ifgroup;
|
||||
|
||||
r = sd_netlink_message_read_u64(message, FRA_TUN_ID, &tmp->tunnel_id);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_warning_errno(r, "rtnl: could not get FRA_TUN_ID attribute, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if (r >= 0)
|
||||
tmp->tunnel_id = be64toh(tmp->tunnel_id);
|
||||
|
||||
r = sd_netlink_message_read_u32(message, FRA_FLOW, &tmp->realms);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_warning_errno(r, "rtnl: could not get FRA_FLOW attribute, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (adjust_protocol)
|
||||
/* As .network files does not have setting to specify protocol, we can assume the
|
||||
* protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
|
||||
tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
|
||||
|
||||
(void) routing_policy_rule_get(m, tmp, &rule);
|
||||
(void) routing_policy_rule_get(m, tmp, tmp->family, &rule);
|
||||
(void) routing_policy_rule_get_request(m, tmp, tmp->family, &req);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWRULE:
|
||||
if (rule) {
|
||||
routing_policy_rule_enter_configured(rule);
|
||||
log_routing_policy_rule_debug(rule, "Received remembered", NULL, m);
|
||||
} else if (!m->manage_foreign_rules) {
|
||||
routing_policy_rule_enter_configured(tmp);
|
||||
log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
|
||||
} else {
|
||||
routing_policy_rule_enter_configured(tmp);
|
||||
log_routing_policy_rule_debug(tmp, "Remembering", NULL, m);
|
||||
r = routing_policy_rule_attach(m, tmp);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RTM_DELRULE:
|
||||
if (type == RTM_DELRULE) {
|
||||
if (rule) {
|
||||
routing_policy_rule_enter_removed(rule);
|
||||
if (rule->state == 0) {
|
||||
log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
|
||||
routing_policy_rule_detach(rule);
|
||||
} else
|
||||
log_routing_policy_rule_debug(rule, "Removed", NULL, m);
|
||||
log_routing_policy_rule_debug(rule, "Forgetting removed", NULL, m);
|
||||
routing_policy_rule_detach(rule);
|
||||
} else
|
||||
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
if (req)
|
||||
routing_policy_rule_enter_removed(req->userdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rule) {
|
||||
if (!req && !m->manage_foreign_rules) {
|
||||
routing_policy_rule_enter_configured(tmp);
|
||||
log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we did not know the rule, then save it. */
|
||||
r = routing_policy_rule_attach(m, tmp);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to save received routing policy rule, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rule = tmp;
|
||||
is_new = true;
|
||||
}
|
||||
|
||||
/* Also update information that cannot be obtained through netlink notification. */
|
||||
if (req && req->waiting_reply) {
|
||||
RoutingPolicyRule *req_rule = ASSERT_PTR(req->userdata);
|
||||
|
||||
rule->source = req_rule->source;
|
||||
}
|
||||
|
||||
/* Then, update miscellaneous info from netlink notification. */
|
||||
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &rule->flags);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
|
||||
|
||||
r = sd_netlink_message_read_u32(message, FRA_GOTO, &rule->priority_goto);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
log_debug_errno(r, "rtnl: could not get FRA_GOTO attribute, ignoring: %m");
|
||||
|
||||
routing_policy_rule_enter_configured(rule);
|
||||
if (req)
|
||||
routing_policy_rule_enter_configured(req->userdata);
|
||||
|
||||
log_routing_policy_rule_debug(rule, is_new ? "Remembering" : "Received remembered", NULL, m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1239,6 +1426,48 @@ int config_parse_routing_policy_rule_priority(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_routing_policy_rule_goto(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_unref_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = ASSERT_PTR(userdata);
|
||||
uint32_t priority;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = safe_atou32(rvalue, &priority);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=%s, ignoring assignment: %m", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (priority <= 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid goto target priority, ignoring assignment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->type = FR_ACT_GOTO;
|
||||
n->priority_goto = priority;
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_routing_policy_rule_table(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@@ -1795,6 +2024,23 @@ static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
|
||||
if (rule->l3mdev)
|
||||
rule->table = RT_TABLE_UNSPEC;
|
||||
|
||||
if (rule->type == FR_ACT_GOTO) {
|
||||
if (rule->priority_goto <= 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Type=goto is specified but the target priority GoTo= is unspecified. "
|
||||
"Ignoring [RoutingPolicyRule] section from line %u.",
|
||||
rule->section->filename,
|
||||
rule->section->line);
|
||||
|
||||
if (rule->priority_set && rule->priority >= rule->priority_goto)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: goto target priority %"PRIu32" must be larger than the priority of this rule %"PRIu32". "
|
||||
"Ignoring [RoutingPolicyRule] section from line %u.",
|
||||
rule->section->filename,
|
||||
rule->priority_goto, rule->priority,
|
||||
rule->section->line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ typedef struct RoutingPolicyRule {
|
||||
union in_addr_union to; /* FRA_DST */
|
||||
union in_addr_union from; /* FRA_SRC */
|
||||
char *iif; /* FRA_IIFNAME */
|
||||
/* FRA_GOTO */
|
||||
uint32_t priority_goto; /* FRA_GOTO */
|
||||
bool priority_set;
|
||||
uint32_t priority; /* FRA_PRIORITY */
|
||||
uint32_t fwmark; /* FRA_FWMARK */
|
||||
/* FRA_FLOW */
|
||||
/* FRA_TUN_ID */
|
||||
uint32_t realms; /* FRA_FLOW (IPv4 only) */
|
||||
uint64_t tunnel_id; /* FRA_TUN_ID */
|
||||
int32_t suppress_ifgroup; /* FRA_SUPPRESS_IFGROUP */
|
||||
int32_t suppress_prefixlen; /* FRA_SUPPRESS_PREFIXLEN */
|
||||
uint32_t table; /* FRA_TABLE, also used in struct fib_rule_hdr */
|
||||
@@ -54,7 +54,8 @@ typedef struct RoutingPolicyRule {
|
||||
struct fib_rule_port_range dport; /* FRA_DPORT_RANGE */
|
||||
} RoutingPolicyRule;
|
||||
|
||||
const char* fr_act_type_full_to_string(int t) _const_;
|
||||
int fr_act_type_from_string(const char *s) _pure_;
|
||||
const char* fr_act_type_to_string(int t) _const_;
|
||||
|
||||
RoutingPolicyRule* routing_policy_rule_ref(RoutingPolicyRule *rule);
|
||||
RoutingPolicyRule* routing_policy_rule_unref(RoutingPolicyRule *rule);
|
||||
@@ -81,6 +82,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_fwmark_mask);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_prefix);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_priority);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_goto);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_device);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_l3mdev);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_port_range);
|
||||
|
||||
@@ -112,6 +112,7 @@ int sd_netlink_message_read_strv(sd_netlink_message *m, uint16_t container_type,
|
||||
int sd_netlink_message_read_u8(sd_netlink_message *m, uint16_t attr_type, uint8_t *data);
|
||||
int sd_netlink_message_read_u16(sd_netlink_message *m, uint16_t attr_type, uint16_t *data);
|
||||
int sd_netlink_message_read_u32(sd_netlink_message *m, uint16_t attr_type, uint32_t *data);
|
||||
int sd_netlink_message_read_u64(sd_netlink_message *m, uint16_t attr_type, uint64_t *ret);
|
||||
int sd_netlink_message_read_ether_addr(sd_netlink_message *m, uint16_t attr_type, struct ether_addr *data);
|
||||
int sd_netlink_message_read_cache_info(sd_netlink_message *m, uint16_t attr_type, struct ifa_cacheinfo *info);
|
||||
int sd_netlink_message_read_in_addr(sd_netlink_message *m, uint16_t attr_type, struct in_addr *data);
|
||||
|
||||
@@ -27,7 +27,23 @@ Priority=101
|
||||
Family=both
|
||||
|
||||
[RoutingPolicyRule]
|
||||
Type=table
|
||||
IncomingInterface=test1
|
||||
From=0.0.0.0/8
|
||||
Table=10
|
||||
Priority=102
|
||||
|
||||
[RoutingPolicyRule]
|
||||
Type=goto
|
||||
IncomingInterface=test1
|
||||
From=10.0.0.0/16
|
||||
Priority=103
|
||||
GoTo=111
|
||||
Table=11
|
||||
|
||||
[RoutingPolicyRule]
|
||||
Type=nop
|
||||
IncomingInterface=test1
|
||||
From=10.1.0.0/16
|
||||
Priority=104
|
||||
Table=12
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Network]
|
||||
ManageForeignRoutingPolicyRules=no
|
||||
@@ -645,7 +645,7 @@ def flush_routing_policy_rules():
|
||||
have = True
|
||||
print(f'### Removing IPv{ipv} routing policy rules that did not exist when the test started.')
|
||||
print(f'# {line}')
|
||||
words = line.replace('lookup [l3mdev-table]', 'l3mdev').split()
|
||||
words = line.replace('lookup [l3mdev-table]', 'l3mdev').replace('[detached]', '').split()
|
||||
priority = words[0].rstrip(':')
|
||||
call(f'ip -{ipv} rule del priority {priority} ' + ' '.join(words[1:]))
|
||||
|
||||
@@ -3210,43 +3210,80 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
self.assertNotRegex(output, '192.168.0.1')
|
||||
self.assertRegex(output, routable_map[carrier])
|
||||
|
||||
def test_routing_policy_rule(self):
|
||||
copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev')
|
||||
start_networkd()
|
||||
self.wait_online('test1:degraded')
|
||||
|
||||
def check_routing_policy_rule_test1(self):
|
||||
output = check_output('ip rule list iif test1 priority 111')
|
||||
print(output)
|
||||
self.assertRegex(output, '111:')
|
||||
self.assertRegex(output, 'from 192.168.100.18')
|
||||
self.assertRegex(output, r'tos (0x08|throughput)\s')
|
||||
self.assertRegex(output, 'iif test1')
|
||||
self.assertRegex(output, 'oif test1')
|
||||
self.assertRegex(output, 'lookup 7')
|
||||
|
||||
output = check_output('ip rule list iif test1 priority 101')
|
||||
print(output)
|
||||
self.assertRegex(output, '101:')
|
||||
self.assertRegex(output, 'from all')
|
||||
self.assertRegex(output, 'iif test1')
|
||||
self.assertRegex(output, 'lookup 9')
|
||||
self.assertRegex(output, r'111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
|
||||
|
||||
output = check_output('ip -6 rule list iif test1 priority 100')
|
||||
print(output)
|
||||
self.assertRegex(output, '100:')
|
||||
self.assertRegex(output, 'from all')
|
||||
self.assertRegex(output, 'iif test1')
|
||||
self.assertRegex(output, 'lookup 8')
|
||||
self.assertIn('100: from all iif test1 lookup 8', output)
|
||||
|
||||
output = check_output('ip rule list iif test1 priority 101')
|
||||
print(output)
|
||||
self.assertIn('101: from all iif test1 lookup 9', output)
|
||||
|
||||
output = check_output('ip rule list iif test1 priority 102')
|
||||
print(output)
|
||||
self.assertRegex(output, '102:')
|
||||
self.assertRegex(output, 'from 0.0.0.0/8')
|
||||
self.assertRegex(output, 'iif test1')
|
||||
self.assertRegex(output, 'lookup 10')
|
||||
self.assertIn('102: from 0.0.0.0/8 iif test1 lookup 10', output)
|
||||
|
||||
output = check_output('ip rule list iif test1 priority 103')
|
||||
print(output)
|
||||
self.assertIn('103: from 10.0.0.0/16 iif test1 lookup 11 goto 111', output)
|
||||
|
||||
output = check_output('ip rule list iif test1 priority 104')
|
||||
print(output)
|
||||
self.assertIn('104: from 10.1.0.0/16 iif test1 lookup 12 nop', output)
|
||||
|
||||
def check_routing_policy_rule_dummy98(self):
|
||||
output = check_output('ip rule list table 8')
|
||||
print(output)
|
||||
self.assertRegex(output, r'112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
|
||||
|
||||
def _test_routing_policy_rule(self, manage_foreign_routes):
|
||||
if not manage_foreign_routes:
|
||||
copy_networkd_conf_dropin('networkd-manage-foreign-rules-no.conf')
|
||||
copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev')
|
||||
|
||||
stop_networkd()
|
||||
|
||||
check_output('ip -4 rule add priority 20001 table 9999 from 10.10.0.0/16')
|
||||
check_output('ip -6 rule add priority 20001 table 9999 from 2001:db8:0:1::/64')
|
||||
|
||||
start_networkd()
|
||||
self.wait_online('test1:degraded')
|
||||
|
||||
self.check_routing_policy_rule_test1()
|
||||
check_json(networkctl_json())
|
||||
|
||||
output = check_output('ip -4 rule list priority 20001 table 9999 from 10.10.0.0/16')
|
||||
print(output)
|
||||
if manage_foreign_routes:
|
||||
self.assertEqual(output, '')
|
||||
else:
|
||||
self.assertIn(output, '20001: from 10.10.0.0/16 lookup 9999')
|
||||
check_output('ip -4 rule del priority 20001 table 9999 from 10.10.0.0/16')
|
||||
|
||||
output = check_output('ip -6 rule list priority 20001 table 9999 from 2001:db8:0:1::/64')
|
||||
print(output)
|
||||
if manage_foreign_routes:
|
||||
self.assertEqual(output, '')
|
||||
else:
|
||||
self.assertIn(output, '20001: from 2001:db8:0:1::/64 lookup 9999')
|
||||
check_output('ip -6 rule del priority 20001 table 9999 from 2001:db8:0:1::/64')
|
||||
|
||||
def test_routing_policy_rule(self):
|
||||
first = True
|
||||
for manage_foreign_routes in [True, False]:
|
||||
if first:
|
||||
first = False
|
||||
else:
|
||||
self.tearDown()
|
||||
|
||||
print(f'### test_routing_policy_rule(manage_foreign_routes={manage_foreign_routes})')
|
||||
with self.subTest(manage_foreign_routes=manage_foreign_routes):
|
||||
self._test_routing_policy_rule(manage_foreign_routes)
|
||||
|
||||
def test_routing_policy_rule_issue_11280(self):
|
||||
copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev',
|
||||
'25-routing-policy-rule-dummy98.network', '12-dummy.netdev')
|
||||
@@ -3255,13 +3292,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
restart_networkd(show_logs=(trial > 0))
|
||||
self.wait_online('test1:degraded', 'dummy98:degraded')
|
||||
|
||||
output = check_output('ip rule list table 7')
|
||||
print(output)
|
||||
self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
|
||||
|
||||
output = check_output('ip rule list table 8')
|
||||
print(output)
|
||||
self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
|
||||
self.check_routing_policy_rule_test1()
|
||||
self.check_routing_policy_rule_dummy98()
|
||||
|
||||
def test_routing_policy_rule_reconfigure(self):
|
||||
copy_network_unit('25-routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
|
||||
|
||||
Reference in New Issue
Block a user