From 5424fd9573e8c41660cc90c975fb2bee74d927b1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 07:46:08 +0900 Subject: [PATCH 1/9] test-network: test more bridge properties Imported from networkd-test.py --- .../conf/26-bridge-slave-interface-1.network | 3 +++ .../conf/26-bridge-slave-interface-2.network | 3 +++ test/test-network/systemd-networkd-tests.py | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/test-network/conf/26-bridge-slave-interface-1.network b/test/test-network/conf/26-bridge-slave-interface-1.network index 1f8c5b5648..6aed178525 100644 --- a/test/test-network/conf/26-bridge-slave-interface-1.network +++ b/test/test-network/conf/26-bridge-slave-interface-1.network @@ -13,3 +13,6 @@ MulticastFlood = false MulticastToUnicast = true NeighborSuppression = true Learning = false +Priority = 23 +UseBPDU = true +AllowPortToBeRoot=true diff --git a/test/test-network/conf/26-bridge-slave-interface-2.network b/test/test-network/conf/26-bridge-slave-interface-2.network index 45ec2de999..5fccfec5d1 100644 --- a/test/test-network/conf/26-bridge-slave-interface-2.network +++ b/test/test-network/conf/26-bridge-slave-interface-2.network @@ -3,3 +3,6 @@ Name=test1 [Network] Bridge=bridge99 + +[Bridge] +Priority=0 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 399824af5c..17ec04cbdb 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2007,18 +2007,24 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): output = check_output('bridge -d link show dummy98') print(output) - self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1') self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1') self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1') self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0') - self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1') - if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')): - self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1') - self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0') - # CONFIG_BRIDGE_IGMP_SNOOPING=y if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')): self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1') + if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')): + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1') + self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1') + + output = check_output('bridge -d link show test1') + print(output) + self.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0') check_output('ip address add 192.168.0.16/24 dev bridge99') time.sleep(1) From 7a22312d6876290ede6576a9793ab9a654fe173d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 08:43:33 +0900 Subject: [PATCH 2/9] network: use string table to parse route type --- src/network/networkd-route.c | 31 ++++++++++++++++++------------- src/network/networkd-route.h | 3 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index f79d5b2057..618d250899 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -12,6 +12,7 @@ #include "networkd-route.h" #include "parse-util.h" #include "set.h" +#include "string-table.h" #include "string-util.h" #include "sysctl-util.h" #include "util.h" @@ -749,6 +750,17 @@ int network_add_default_route_on_device(Network *network) { return 0; } +static const char * const route_type_table[__RTN_MAX] = { + [RTN_UNICAST] = "unicast", + [RTN_BLACKHOLE] = "blackhole", + [RTN_UNREACHABLE] = "unreachable", + [RTN_PROHIBIT] = "prohibit", + [RTN_THROW] = "throw", +}; + +assert_cc(__RTN_MAX <= UCHAR_MAX); +DEFINE_STRING_TABLE_LOOKUP(route_type, int); + int config_parse_gateway( const char *unit, const char *filename, @@ -1127,28 +1139,21 @@ int config_parse_route_type( Network *network = userdata; _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - int r; + int t, r; r = route_new_static(network, filename, section_line, &n); if (r < 0) return r; - if (streq(rvalue, "unicast")) - n->type = RTN_UNICAST; - else if (streq(rvalue, "blackhole")) - n->type = RTN_BLACKHOLE; - else if (streq(rvalue, "unreachable")) - n->type = RTN_UNREACHABLE; - else if (streq(rvalue, "prohibit")) - n->type = RTN_PROHIBIT; - else if (streq(rvalue, "throw")) - n->type = RTN_THROW; - else { - log_syntax(unit, LOG_ERR, filename, line, r, + t = route_type_from_string(rvalue); + if (t < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue); return 0; } + n->type = (unsigned char) t; + TAKE_PTR(n); return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 3c0ac896ae..e7bd61eb9e 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -65,6 +65,9 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free); int network_add_ipv4ll_route(Network *network); int network_add_default_route_on_device(Network *network); +const char* route_type_to_string(int t) _const_; +int route_type_from_string(const char *s) _pure_; + CONFIG_PARSER_PROTOTYPE(config_parse_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src); CONFIG_PARSER_PROTOTYPE(config_parse_destination); From 94d6e299637db582f156612af32f167643caf4c9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 09:40:17 +0900 Subject: [PATCH 3/9] network: make Route.Type= support local, broadcast, anycast, multicast, nat, and xresolve Closes #12975. --- man/systemd.network.xml | 6 +++++- src/network/networkd-route.c | 22 ++++++++++++++++++++++ src/network/networkd-route.h | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 612450dbd8..70abb14c45 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1232,7 +1232,11 @@ Type= - Specifies the type for the route. If unicast, a regular route is defined, i.e. a + Specifies the type for the route. Takes one of unicast, + local, broadcast, anycast, + multicast, blackhole, unreachable, + prohibit, throw, nat, and + xresolve. If unicast, a regular route is defined, i.e. a route indicating the path to take to a destination network address. If blackhole, packets to the defined route are discarded silently. If unreachable, packets to the defined route are discarded and the ICMP message "Host Unreachable" is generated. If prohibit, packets diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 618d250899..f13214c5ee 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -719,6 +719,8 @@ int network_add_ipv4ll_route(Network *network) { n->family = AF_INET; n->dst_prefixlen = 16; n->scope = RT_SCOPE_LINK; + n->scope_set = true; + n->table_set = true; n->priority = IPV4LL_ROUTE_METRIC; n->protocol = RTPROT_STATIC; @@ -752,10 +754,16 @@ int network_add_default_route_on_device(Network *network) { static const char * const route_type_table[__RTN_MAX] = { [RTN_UNICAST] = "unicast", + [RTN_LOCAL] = "local", + [RTN_BROADCAST] = "broadcast", + [RTN_ANYCAST] = "anycast", + [RTN_MULTICAST] = "multicast", [RTN_BLACKHOLE] = "blackhole", [RTN_UNREACHABLE] = "unreachable", [RTN_PROHIBIT] = "prohibit", [RTN_THROW] = "throw", + [RTN_NAT] = "nat", + [RTN_XRESOLVE] = "xresolve", }; assert_cc(__RTN_MAX <= UCHAR_MAX); @@ -971,6 +979,7 @@ int config_parse_route_scope( return 0; } + n->scope_set = true; TAKE_PTR(n); return 0; } @@ -1008,6 +1017,7 @@ int config_parse_route_table( return 0; } + n->table_set = true; TAKE_PTR(n); return 0; } @@ -1371,6 +1381,18 @@ int route_section_verify(Route *route, Network *network) { route->section->filename, route->section->line); } + if (route->family != AF_INET6) { + if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT)) + route->table = RT_TABLE_LOCAL; + + if (!route->scope_set) { + if (IN_SET(route->type, RTN_LOCAL, RTN_NAT)) + route->scope = RT_SCOPE_HOST; + else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST)) + route->scope = RT_SCOPE_LINK; + } + } + if (network->n_static_addresses == 0 && in_addr_is_null(route->family, &route->gw) == 0 && route->gateway_onlink < 0) { diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index e7bd61eb9e..2f0d052325 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -23,11 +23,13 @@ struct Route { unsigned char dst_prefixlen; unsigned char src_prefixlen; unsigned char scope; + bool scope_set; unsigned char protocol; /* RTPROT_* */ unsigned char type; /* RTN_* */ unsigned char tos; uint32_t priority; /* note that ip(8) calls this 'metric' */ uint32_t table; + bool table_set; uint32_t mtu; uint32_t initcwnd; uint32_t initrwnd; From 39f26098c94a6d931e6d6757ac50c24ecf362e18 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 20:34:54 +0900 Subject: [PATCH 4/9] network: update log message Follow-up for 7f474ed78df138677557fb43701efeb6e2588c6f and 44e891bbf6908e494856fcf3011e88a70a12e087. --- src/network/networkd-manager.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 33b7ec1d6c..5b2581a3ee 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -298,7 +298,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex); if (r == -ENODATA) { - log_debug("rtnl: received route without ifindex, ignoring"); + log_debug("rtnl: received route message without ifindex, ignoring"); return 0; } else if (r < 0) { log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m"); @@ -313,7 +313,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo /* when enumerating we might be out of sync, but we will * get the route again, so just ignore it */ if (!m->enumerating) - log_warning("rtnl: received route for link (%d) we do not know about, ignoring", ifindex); + log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex); return 0; } @@ -391,43 +391,43 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m"); return 0; } r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m"); return 0; } r = sd_rtnl_message_route_get_scope(message, &scope); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m"); return 0; } r = sd_rtnl_message_route_get_tos(message, &tos); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m"); return 0; } r = sd_rtnl_message_route_get_type(message, &rt_type); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid type, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m"); return 0; } r = sd_rtnl_message_route_get_table(message, &table); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m"); return 0; } r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority); if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m"); + log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m"); return 0; } From b297e0a7b097322e0cb3f1ee47d8429a121a031f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 21:50:05 +0900 Subject: [PATCH 5/9] network: show route scope, table, and type in debugging logs --- src/network/networkd-manager.c | 8 +++- src/network/networkd-route.c | 75 +++++++++++++++++++++++++++++++++- src/network/networkd-route.h | 7 ++++ 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 5b2581a3ee..69af9746e0 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -436,6 +436,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo if (DEBUG_LOGGING) { _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL, *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL; + char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX]; if (!in_addr_is_null(family, &dst)) { (void) in_addr_to_string(family, &dst, &buf_dst); @@ -449,10 +450,13 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo (void) in_addr_to_string(family, &prefsrc, &buf_prefsrc); log_link_debug(link, - "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s", + "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", type == RTM_DELROUTE ? "Forgetting" : route ? "Updating remembered" : "Remembering", strna(buf_dst), strempty(buf_dst_prefixlen), - strna(buf_src), strna(buf_gw), strna(buf_prefsrc)); + strna(buf_src), strna(buf_gw), strna(buf_prefsrc), + format_route_scope(scope, buf_scope, sizeof buf_scope), + format_route_table(table, buf_table, sizeof buf_table), + strna(route_type_to_string(rt_type))); } switch (type) { diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index f13214c5ee..98fc8e4fe0 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -14,6 +14,7 @@ #include "set.h" #include "string-table.h" #include "string-util.h" +#include "strxcpyx.h" #include "sysctl-util.h" #include "util.h" @@ -413,6 +414,28 @@ int route_remove(Route *route, Link *link, if (r < 0) return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m"); + if (DEBUG_LOGGING) { + _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; + char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX]; + + if (!in_addr_is_null(route->family, &route->dst)) { + (void) in_addr_to_string(route->family, &route->dst, &dst); + (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen); + } + if (!in_addr_is_null(route->family, &route->src)) + (void) in_addr_to_string(route->family, &route->src, &src); + if (!in_addr_is_null(route->family, &route->gw)) + (void) in_addr_to_string(route->family, &route->gw, &gw); + if (!in_addr_is_null(route->family, &route->prefsrc)) + (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); + + log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", + strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), + format_route_scope(route->scope, scope, sizeof(scope)), + format_route_table(route->table, table, sizeof(table)), + strna(route_type_to_string(route->type))); + } + if (in_addr_is_null(route->family, &route->gw) == 0) { r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw); if (r < 0) @@ -514,6 +537,7 @@ int route_configure( if (DEBUG_LOGGING) { _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; + char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX]; if (!in_addr_is_null(route->family, &route->dst)) { (void) in_addr_to_string(route->family, &route->dst, &dst); @@ -526,8 +550,11 @@ int route_configure( if (!in_addr_is_null(route->family, &route->prefsrc)) (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); - log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s", - strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc)); + log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", + strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), + format_route_scope(route->scope, scope, sizeof(scope)), + format_route_table(route->table, table, sizeof(table)), + strna(route_type_to_string(route->type))); } r = sd_rtnl_message_new_route(link->manager->rtnl, &req, @@ -769,6 +796,50 @@ static const char * const route_type_table[__RTN_MAX] = { assert_cc(__RTN_MAX <= UCHAR_MAX); DEFINE_STRING_TABLE_LOOKUP(route_type, int); +static const char * const route_scope_table[] = { + [RT_SCOPE_UNIVERSE] = "global", + [RT_SCOPE_SITE] = "site", + [RT_SCOPE_LINK] = "link", + [RT_SCOPE_HOST] = "host", + [RT_SCOPE_NOWHERE] = "nowhere", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_scope, int); + +const char *format_route_scope(int scope, char *buf, size_t size) { + const char *s; + char *p = buf; + + s = route_scope_to_string(scope); + if (s) + strpcpy(&p, size, s); + else + strpcpyf(&p, size, "%d", scope); + + return buf; +} + +static const char * const route_table_table[] = { + [RT_TABLE_DEFAULT] = "default", + [RT_TABLE_MAIN] = "main", + [RT_TABLE_LOCAL] = "local", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_table, int); + +const char *format_route_table(int table, char *buf, size_t size) { + const char *s; + char *p = buf; + + s = route_table_to_string(table); + if (s) + strpcpy(&p, size, s); + else + strpcpyf(&p, size, "%d", table); + + return buf; +} + int config_parse_gateway( const char *unit, const char *filename, diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 2f0d052325..d6a023e930 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -2,6 +2,7 @@ #pragma once #include "conf-parser.h" +#include "macro.h" typedef struct Route Route; typedef struct NetworkConfigSection NetworkConfigSection; @@ -70,6 +71,12 @@ int network_add_default_route_on_device(Network *network); const char* route_type_to_string(int t) _const_; int route_type_from_string(const char *s) _pure_; +#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1) +const char *format_route_scope(int scope, char *buf, size_t size); + +#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1) +const char *format_route_table(int table, char *buf, size_t size); + CONFIG_PARSER_PROTOTYPE(config_parse_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src); CONFIG_PARSER_PROTOTYPE(config_parse_destination); From 41b90a1eb5cb87beab4603b52adbce36b723a6d6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Jul 2019 20:19:28 +0900 Subject: [PATCH 6/9] network: use string table to parse route table or scope --- man/systemd.network.xml | 5 +++-- src/network/networkd-route.c | 29 +++++++++++++++-------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 70abb14c45..c9d6fd4d72 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1086,8 +1086,9 @@ Table= - Specifies the routing table identifier to lookup if the rule - selector matches. The table identifier for a route (a number between 1 and 4294967295). + Specifies the routing table identifier to lookup if the rule selector matches. Takes + one of default, main, and local, + or a number between 1 and 4294967295. Defaults to main. diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 98fc8e4fe0..cf09e49018 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -804,7 +804,7 @@ static const char * const route_scope_table[] = { [RT_SCOPE_NOWHERE] = "nowhere", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_scope, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int); const char *format_route_scope(int scope, char *buf, size_t size) { const char *s; @@ -825,7 +825,7 @@ static const char * const route_table_table[] = { [RT_TABLE_LOCAL] = "local", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_table, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int); const char *format_route_table(int table, char *buf, size_t size) { const char *s; @@ -1039,17 +1039,13 @@ int config_parse_route_scope( if (r < 0) return r; - if (streq(rvalue, "host")) - n->scope = RT_SCOPE_HOST; - else if (streq(rvalue, "link")) - n->scope = RT_SCOPE_LINK; - else if (streq(rvalue, "global")) - n->scope = RT_SCOPE_UNIVERSE; - else { + r = route_scope_from_string(rvalue); + if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue); return 0; } + n->scope = r; n->scope_set = true; TAKE_PTR(n); return 0; @@ -1081,11 +1077,16 @@ int config_parse_route_table( if (r < 0) return r; - r = safe_atou32(rvalue, &n->table); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); - 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_ERR, filename, line, r, + "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); + return 0; + } } n->table_set = true; From 1b64651bd192a4cf5f5b2777ad94a37b542bd0a2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Jul 2019 20:36:19 +0900 Subject: [PATCH 7/9] network: use string table for route protocol --- src/network/networkd-route.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index cf09e49018..798c9ed314 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -840,6 +840,14 @@ const char *format_route_table(int table, char *buf, size_t size) { return buf; } +static const char * const route_protocol_table[] = { + [RTPROT_KERNEL] = "kernel", + [RTPROT_BOOT] = "boot", + [RTPROT_STATIC] = "static", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int); + int config_parse_gateway( const char *unit, const char *filename, @@ -1188,12 +1196,9 @@ int config_parse_route_protocol( if (r < 0) return r; - if (streq(rvalue, "kernel")) - n->protocol = RTPROT_KERNEL; - else if (streq(rvalue, "boot")) - n->protocol = RTPROT_BOOT; - else if (streq(rvalue, "static")) - n->protocol = RTPROT_STATIC; + r = route_protocol_from_string(rvalue); + if (r >= 0) + n->protocol = r; else { r = safe_atou8(rvalue , &n->protocol); if (r < 0) { From d3e291fd62bdffab9fd3c71beb25aa8876f77178 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 10 Jul 2019 00:18:53 +0900 Subject: [PATCH 8/9] network: also show route protocol in debugging logs --- src/network/networkd-manager.c | 6 ++++-- src/network/networkd-route.c | 25 ++++++++++++++++++++----- src/network/networkd-route.h | 3 +++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 69af9746e0..ec3bb47ea6 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -436,7 +436,8 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo if (DEBUG_LOGGING) { _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL, *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL; - char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX]; + char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX], + buf_protocol[ROUTE_PROTOCOL_STR_MAX]; if (!in_addr_is_null(family, &dst)) { (void) in_addr_to_string(family, &dst, &buf_dst); @@ -450,12 +451,13 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo (void) in_addr_to_string(family, &prefsrc, &buf_prefsrc); log_link_debug(link, - "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", + "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", type == RTM_DELROUTE ? "Forgetting" : route ? "Updating remembered" : "Remembering", strna(buf_dst), strempty(buf_dst_prefixlen), strna(buf_src), strna(buf_gw), strna(buf_prefsrc), format_route_scope(scope, buf_scope, sizeof buf_scope), format_route_table(table, buf_table, sizeof buf_table), + format_route_protocol(protocol, buf_protocol, sizeof buf_protocol), strna(route_type_to_string(rt_type))); } diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 798c9ed314..ddc0fe279f 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -416,7 +416,7 @@ int route_remove(Route *route, Link *link, if (DEBUG_LOGGING) { _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; - char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX]; + char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX]; if (!in_addr_is_null(route->family, &route->dst)) { (void) in_addr_to_string(route->family, &route->dst, &dst); @@ -429,10 +429,11 @@ int route_remove(Route *route, Link *link, if (!in_addr_is_null(route->family, &route->prefsrc)) (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); - log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", + log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), format_route_scope(route->scope, scope, sizeof(scope)), format_route_table(route->table, table, sizeof(table)), + format_route_protocol(route->protocol, protocol, sizeof(protocol)), strna(route_type_to_string(route->type))); } @@ -537,7 +538,7 @@ int route_configure( if (DEBUG_LOGGING) { _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; - char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX]; + char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX]; if (!in_addr_is_null(route->family, &route->dst)) { (void) in_addr_to_string(route->family, &route->dst, &dst); @@ -550,10 +551,11 @@ int route_configure( if (!in_addr_is_null(route->family, &route->prefsrc)) (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); - log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, type: %s", + log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), format_route_scope(route->scope, scope, sizeof(scope)), format_route_table(route->table, table, sizeof(table)), + format_route_protocol(route->protocol, protocol, sizeof(protocol)), strna(route_type_to_string(route->type))); } @@ -846,7 +848,20 @@ static const char * const route_protocol_table[] = { [RTPROT_STATIC] = "static", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_protocol, int); + +const char *format_route_protocol(int protocol, char *buf, size_t size) { + const char *s; + char *p = buf; + + s = route_protocol_to_string(protocol); + if (s) + strpcpy(&p, size, s); + else + strpcpyf(&p, size, "%d", protocol); + + return buf; +} int config_parse_gateway( const char *unit, diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index d6a023e930..86a7a82617 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -77,6 +77,9 @@ const char *format_route_scope(int scope, char *buf, size_t size); #define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1) const char *format_route_table(int table, char *buf, size_t size); +#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("kernel") + 1) +const char *format_route_protocol(int protocol, char *buf, size_t size); + CONFIG_PARSER_PROTOTYPE(config_parse_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src); CONFIG_PARSER_PROTOTYPE(config_parse_destination); From 6d60f9dbe6d1399fa820b36716518fb9cb4ee2bb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Jul 2019 21:57:22 +0900 Subject: [PATCH 9/9] test-network: add tests for route with type local, multicast, anycast, or broadcast --- test/test-network/conf/25-route-static.network | 16 ++++++++++++++++ test/test-network/systemd-networkd-tests.py | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/test/test-network/conf/25-route-static.network b/test/test-network/conf/25-route-static.network index 9e12480a65..9c8269e3b8 100644 --- a/test/test-network/conf/25-route-static.network +++ b/test/test-network/conf/25-route-static.network @@ -46,3 +46,19 @@ Destination=202.54.1.3 [Route] Type=prohibit Destination=202.54.1.4 + +[Route] +Type=local +Destination=149.10.123.1 + +[Route] +Type=anycast +Destination=149.10.123.2 + +[Route] +Type=broadcast +Destination=149.10.123.3 + +[Route] +Type=multicast +Destination=149.10.123.4 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 17ec04cbdb..e396af05da 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1552,14 +1552,18 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): start_networkd() wait_online(['dummy98:routable']) + print('### ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98') print(output) self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static') self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel') + print('### ip -6 route show dev dummy98 default') output = check_output('ip -6 route show dev dummy98 default') + print(output) self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium') + print('### ip -4 route show dev dummy98') output = check_output('ip -4 route show dev dummy98') print(output) self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58') @@ -1567,20 +1571,33 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048') self.assertRegex(output, '192.168.1.1 proto static initcwnd 20') self.assertRegex(output, '192.168.1.2 proto static initrwnd 30') + self.assertRegex(output, 'multicast 149.10.123.4 proto static') + print('### ip -4 route show dev dummy98 default') output = check_output('ip -4 route show dev dummy98 default') + print(output) self.assertRegex(output, 'default via 149.10.125.65 proto static onlink') self.assertRegex(output, 'default via 149.10.124.64 proto static') self.assertRegex(output, 'default proto static') + print('### ip -4 route show table local dev dummy98') + output = check_output('ip -4 route show table local dev dummy98') + print(output) + self.assertRegex(output, 'local 149.10.123.1 proto static scope host') + self.assertRegex(output, 'anycast 149.10.123.2 proto static scope link') + self.assertRegex(output, 'broadcast 149.10.123.3 proto static scope link') + + print('### ip route show type blackhole') output = check_output('ip route show type blackhole') print(output) self.assertRegex(output, 'blackhole 202.54.1.2 proto static') + print('### ip route show type unreachable') output = check_output('ip route show type unreachable') print(output) self.assertRegex(output, 'unreachable 202.54.1.3 proto static') + print('### ip route show type prohibit') output = check_output('ip route show type prohibit') print(output) self.assertRegex(output, 'prohibit 202.54.1.4 proto static')