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; }