diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 0374dc7cdc..6273274e7a 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1728,6 +1728,18 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix
+
+ GoTo=
+
+ Specifies the target priority used by goto type of rule. Takes an integer
+ in the range 1…4294967295. This must be larger than the priority of this rule specified in
+ Priority=. When specified, Type=goto is implied. This is
+ mandatory when Type=goto.
+
+
+
+
+
IncomingInterface=
@@ -1853,8 +1865,10 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix
Type=
Specifies Routing Policy Database (RPDB) rule type. Takes one of
- blackhole, unreachable or prohibit.
-
+ table, goto, nop,
+ blackhole, unreachable, or prohibit.
+ When goto, the target priority must be specified in GoTo=.
+ Defaults to table.
diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c
index 0a57e6aee0..4eafc62c7e 100644
--- a/src/network/networkd-json.c
+++ b/src/network/networkd-json.c
@@ -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),
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index aa849fe535..b2794f9efd 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -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
diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c
index e7c048f273..44d85d000f 100644
--- a/src/network/networkd-routing-policy-rule.c
+++ b/src/network/networkd-routing-policy-rule.c
@@ -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);
@@ -519,7 +512,8 @@ 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;
@@ -1432,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,
@@ -1988,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;
}
diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h
index 3ca5e73934..c7a0512b44 100644
--- a/src/network/networkd-routing-policy-rule.h
+++ b/src/network/networkd-routing-policy-rule.h
@@ -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);