diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
index 65aecb62567..78b46ad505c 100644
--- a/man/networkd.conf.xml
+++ b/man/networkd.conf.xml
@@ -70,6 +70,14 @@
is false. Defaults to yes.
+
+ RouteTable=
+ Specifies the route table name. Takes a route name and table number separated with a colon.
+ (name:integer. The route table number
+ must be an integer in the range 1..4294967295. This setting can be specified multiple times. If an empty string
+ is specified, then all options specified earlier are cleared. Defaults to unset.
+
+
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 8b7c9ff32a7..0d9f1dce0dc 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1200,8 +1200,9 @@ IPv6Token=prefixstable:2002:da8:1::
Table=
- Specifies the routing table identifier to lookup if the rule selector matches. Takes
- one of default, main, and local,
+ Specifies the routing table identifier to lookup if the rule selector matches. Takes one of predefined names
+ default, main, and local, and names defined in RouteTable=
+ in networkd.conf5,
or a number between 1 and 4294967295. Defaults to main.
@@ -1409,11 +1410,11 @@ IPv6Token=prefixstable:2002:da8:1::
Table=
- The table identifier for the route. Takes default,
- main, local or a number between 1 and 4294967295.
- The table can be retrieved using ip route show table num.
- If unset and Type= is local, broadcast,
- anycast, or nat, then local is used.
+ The table identifier for the route. Takes one of predefined names default, main,
+ and local, and names defined in RouteTable= in networkd.conf
+ 5, or a number between 1 and 4294967295. The table can be retrieved using
+ ip route show table num. If unset and Type= is local,
+ broadcast, anycast, or nat, then local is used.
In other cases, defaults to main.
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
index aaabb3d1b32..2860875a0f6 100644
--- a/src/network/networkd-gperf.gperf
+++ b/src/network/networkd-gperf.gperf
@@ -6,6 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "conf-parser.h"
#include "networkd-conf.h"
#include "networkd-manager.h"
+#include "networkd-route.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -21,5 +22,6 @@ struct ConfigPerfItem;
Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter)
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
+Network.RouteTable, config_parse_route_table_names, 0, offsetof(Manager, route_tables)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 47f0edf209b..bf15ba65352 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -875,6 +875,8 @@ void manager_free(Manager *m) {
ordered_set_free_free(m->address_pools);
+ m->route_tables = hashmap_free_free_key(m->route_tables);
+
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */
m->rules = set_free(m->rules);
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 78ba2b0945d..88b9f6bd235 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -65,6 +65,9 @@ struct Manager {
Set *routes;
Set *routes_foreign;
+ /* Route table name */
+ Hashmap *route_tables;
+
/* For link speed meter*/
bool use_speed_meter;
sd_event_source *speed_meter_event_source;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 3142bd686f4..cfb9befc614 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -87,7 +87,7 @@ static const char * const route_table_table[] = {
[RT_TABLE_LOCAL] = "local",
};
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
+DEFINE_STRING_TABLE_LOOKUP(route_table, int);
#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
static const char *format_route_table(int table, char *buf, size_t size) {
@@ -1868,6 +1868,28 @@ int config_parse_route_scope(
return 0;
}
+int route_table_from_string_full(Manager *m, const char *s, uint32_t *ret) {
+ int r;
+
+ assert(s);
+ assert(m);
+ assert(ret);
+
+ r = route_table_from_string(s);
+ if (r >= 0) {
+ *ret = (uint32_t) r;
+ return 0;
+ }
+
+ uint32_t t = PTR_TO_UINT32(hashmap_get(m->route_tables, s));
+ if (t != 0) {
+ *ret = t;
+ return 0;
+ }
+
+ return safe_atou32(s, ret);
+}
+
int config_parse_route_table(
const char *unit,
const char *filename,
@@ -1899,16 +1921,11 @@ int config_parse_route_table(
return 0;
}
- r = route_table_from_string(rvalue);
- if (r >= 0)
- n->table = r;
- else {
- r = safe_atou32(rvalue, &n->table);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
- return 0;
- }
+ r = route_table_from_string_full(network->manager, rvalue, &n->table);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
}
n->table_set = true;
@@ -2356,6 +2373,77 @@ int config_parse_multipath_route(
return 0;
}
+int config_parse_route_table_names(
+ 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_free_ char *name = NULL;
+ Hashmap **s = data;
+ uint32_t table;
+ const char *p;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *s = hashmap_free_free_key(*s);
+ return 0;
+ }
+
+ p = rvalue;
+ r = extract_first_word(&p, &name, ":", 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r <= 0 || isempty(p)) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Invalid RouteTable=, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (STR_IN_SET(name, "default", "main","local")) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Route table name %s already preconfigured. Ignoring assignment: %s", name, rvalue);
+ return 0;
+ }
+
+ r = safe_atou32(p, &table);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse RouteTable=, ignoring assignment: %s", p);
+ return 0;
+ }
+
+ if (table == 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid RouteTable=, ignoring assignment: %s", p);
+ return 0;
+ }
+
+ r = hashmap_ensure_put(s, &string_hash_ops, name, UINT32_TO_PTR(table));
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r == -EEXIST) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Specified RouteTable= name and value pair conflicts with others, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+ if (r > 0)
+ TAKE_PTR(name);
+
+ return 0;
+}
+
static int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section))
return -EINVAL;
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 8923966ddf3..28f6f29128f 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -86,6 +86,11 @@ int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(Network *network);
void network_drop_invalid_routes(Network *network);
+int route_table_from_string_full(Manager *m, const char *table, uint32_t *ret);
+
+const char *route_table_to_string(int d) _const_;
+int route_table_from_string(const char *d) _pure_;
+
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
CONFIG_PARSER_PROTOTYPE(config_parse_destination);
@@ -100,3 +105,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window);
CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss);
+CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names);
diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c
index 6e00e5f9cb6..3534232822e 100644
--- a/src/network/networkd-routing-policy-rule.c
+++ b/src/network/networkd-routing-policy-rule.c
@@ -8,6 +8,7 @@
#include "conf-parser.h"
#include "fileio.h"
#include "format-util.h"
+#include "hashmap.h"
#include "ip-protocol-list.h"
#include "netlink-util.h"
#include "networkd-manager.h"
@@ -1129,9 +1130,10 @@ int config_parse_routing_policy_rule_table(
if (r < 0)
return log_oom();
- r = safe_atou32(rvalue, &n->table);
+ r = route_table_from_string_full(network->manager, rvalue, &n->table);
if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Could not parse RPDB rule route table number \"%s\", ignoring assignment: %m", rvalue);
return 0;
}