From: João Taveira Araújo Date: Thu, 16 Apr 2026 19:13:30 +0000 (-0700) Subject: networkd: allow route table names for VRF.Table= X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bbadd35596949678009e3f5a7cf4689853998b79;p=thirdparty%2Fsystemd.git networkd: allow route table names for VRF.Table= Allow `[VRF] Table=` to accept route table names in addition to numeric table identifiers. These may be predefined route table names or names configured with `networkd.conf` `RouteTable=`. There was an earlier attempt to make `VRF.Table=` accept names in f98dd1e707, but it wired the setting to `config_parse_route_table()`. That parser was a `[Route]` section parser, not a generic scalar parser for netdevs: it expected network/route parser state and created a `Route` object. It was therefore reverted by 40352cf0c1. This commit replaces the uint32 parser with `manager_get_route_table_from_string()`, the generic table parser already used by route/rule, DHCP/RA `RouteTable=`, and WireGuard `RouteTable=` in `.netdev` files. The VRF semantics stay unchanged. The commit retains the existing behavior of the deprecated `TableId=` field. Co-developed-by: OpenAI Codex --- diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 6a84b7a648c..6879518b4b8 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -2683,7 +2683,10 @@ Ports=eth2 Table= - The numeric routing table identifier. This setting is compulsory. + The routing table identifier. Takes a route table name or number. Route table names + may be predefined or configured with RouteTable= in + networkd.conf5. + This setting is compulsory. diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 250b6cf7bcd..269a9745424 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -249,7 +249,7 @@ Bridge.MulticastIGMPVersion, config_parse_bridge_igmp_version, Bridge.FDBMaxLearned, config_parse_bridge_fdb_max_learned, 0, offsetof(Bridge, fdb_max_learned) Bridge.LinkLocalLearning, config_parse_tristate, 0, offsetof(Bridge, linklocal_learn) VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table) /* deprecated */ -VRF.Table, config_parse_uint32, 0, offsetof(Vrf, table) +VRF.Table, config_parse_vrf_table, 0, offsetof(Vrf, table) BareUDP.DestinationPort, config_parse_ip_port, 0, offsetof(BareUDP, dest_port) BareUDP.MinSourcePort, config_parse_ip_port, 0, offsetof(BareUDP, min_port) BareUDP.EtherType, config_parse_bare_udp_iftype, 0, offsetof(BareUDP, iftype) diff --git a/src/network/netdev/vrf.c b/src/network/netdev/vrf.c index 540c269f2d3..d91ccf394ae 100644 --- a/src/network/netdev/vrf.c +++ b/src/network/netdev/vrf.c @@ -4,8 +4,40 @@ #include "sd-netlink.h" +#include "networkd-route-util.h" #include "vrf.h" +int config_parse_vrf_table( + 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) { + + Vrf *vrf = ASSERT_PTR(userdata); + uint32_t *table = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = manager_get_route_table_from_string(vrf->meta.manager, rvalue, table); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", + lvalue, rvalue); + return 0; + } + + return 0; +} + static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { assert(!link); assert(m); diff --git a/src/network/netdev/vrf.h b/src/network/netdev/vrf.h index 7bf94478567..a794c237c98 100644 --- a/src/network/netdev/vrf.h +++ b/src/network/netdev/vrf.h @@ -11,3 +11,5 @@ typedef struct Vrf { DEFINE_NETDEV_CAST(VRF, Vrf); extern const NetDevVTable vrf_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_vrf_table); diff --git a/src/network/test-network.c b/src/network/test-network.c index 6582d3b0740..ab3a86e10b1 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -11,6 +11,7 @@ #include "networkd-route-util.h" #include "strv.h" #include "tests.h" +#include "vrf.h" TEST(deserialize_in_addr) { _cleanup_free_ struct in_addr *addresses = NULL; @@ -150,6 +151,29 @@ TEST(route_tables) { test_route_tables_one(manager, "local", 255); } +TEST(vrf_table) { + _cleanup_(manager_freep) Manager *manager = NULL; + Vrf vrf = {}; + + ASSERT_OK(manager_new(&manager, /* test_mode= */ true)); + ASSERT_OK(manager_setup(manager)); + + vrf.meta.manager = manager; + + ASSERT_OK(config_parse_vrf_table("netdev", "filename", 1, "VRF", 1, "Table", 0, "default", &vrf.table, &vrf)); + ASSERT_EQ(vrf.table, 253U); + + ASSERT_OK(config_parse_route_table_names("manager", "filename", 1, "section", 1, "RouteTable", 0, "vrf-test:1234", manager, manager)); + ASSERT_OK(config_parse_vrf_table("netdev", "filename", 1, "VRF", 1, "Table", 0, "vrf-test", &vrf.table, &vrf)); + ASSERT_EQ(vrf.table, 1234U); + + ASSERT_OK(config_parse_vrf_table("netdev", "filename", 1, "VRF", 1, "Table", 0, "5678", &vrf.table, &vrf)); + ASSERT_EQ(vrf.table, 5678U); + + ASSERT_OK(config_parse_vrf_table("netdev", "filename", 1, "VRF", 1, "Table", 0, "no-such-table", &vrf.table, &vrf)); + ASSERT_EQ(vrf.table, 5678U); +} + TEST(manager_enumerate) { _cleanup_(manager_freep) Manager *manager = NULL;