1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-12 13:18:14 +03:00

Merge pull request #13031 from yuwata/network-route-type-local-12975-2

network: make Route.Type= support local or friends
This commit is contained in:
Yu Watanabe 2019-07-12 14:31:50 +09:00 committed by GitHub
commit a04285c6b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 243 additions and 53 deletions

View File

@ -1086,8 +1086,9 @@
<varlistentry>
<term><varname>Table=</varname></term>
<listitem>
<para>Specifies the routing table identifier to lookup if the rule
selector matches. The table identifier for a route (a number between 1 and 4294967295).</para>
<para>Specifies the routing table identifier to lookup if the rule selector matches. Takes
one of <literal>default</literal>, <literal>main</literal>, and <literal>local</literal>,
or a number between 1 and 4294967295. Defaults to <literal>main</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -1232,7 +1233,11 @@
<varlistentry>
<term><varname>Type=</varname></term>
<listitem>
<para>Specifies the type for the route. If <literal>unicast</literal>, a regular route is defined, i.e. a
<para>Specifies the type for the route. Takes one of <literal>unicast</literal>,
<literal>local</literal>, <literal>broadcast</literal>, <literal>anycast</literal>,
<literal>multicast</literal>, <literal>blackhole</literal>, <literal>unreachable</literal>,
<literal>prohibit</literal>, <literal>throw</literal>, <literal>nat</literal>, and
<literal>xresolve</literal>. If <literal>unicast</literal>, a regular route is defined, i.e. a
route indicating the path to take to a destination network address. If <literal>blackhole</literal>, packets
to the defined route are discarded silently. If <literal>unreachable</literal>, packets to the defined route
are discarded and the ICMP message "Host Unreachable" is generated. If <literal>prohibit</literal>, packets

View File

@ -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;
}
@ -436,6 +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],
buf_protocol[ROUTE_PROTOCOL_STR_MAX];
if (!in_addr_is_null(family, &dst)) {
(void) in_addr_to_string(family, &dst, &buf_dst);
@ -449,10 +451,14 @@ 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, 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));
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)));
}
switch (type) {

View File

@ -12,7 +12,9 @@
#include "networkd-route.h"
#include "parse-util.h"
#include "set.h"
#include "string-table.h"
#include "string-util.h"
#include "strxcpyx.h"
#include "sysctl-util.h"
#include "util.h"
@ -412,6 +414,29 @@ 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], protocol[ROUTE_PROTOCOL_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, 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)));
}
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)
@ -513,6 +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], protocol[ROUTE_PROTOCOL_STR_MAX];
if (!in_addr_is_null(route->family, &route->dst)) {
(void) in_addr_to_string(route->family, &route->dst, &dst);
@ -525,8 +551,12 @@ 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, 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)));
}
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
@ -718,6 +748,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;
@ -749,6 +781,88 @@ int network_add_default_route_on_device(Network *network) {
return 0;
}
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);
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(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(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;
}
static const char * const route_protocol_table[] = {
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
};
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,
const char *filename,
@ -948,17 +1062,14 @@ 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;
}
@ -989,13 +1100,19 @@ 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;
TAKE_PTR(n);
return 0;
}
@ -1094,12 +1211,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) {
@ -1127,28 +1241,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;
}
@ -1366,6 +1473,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) {

View File

@ -2,6 +2,7 @@
#pragma once
#include "conf-parser.h"
#include "macro.h"
typedef struct Route Route;
typedef struct NetworkConfigSection NetworkConfigSection;
@ -23,11 +24,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;
@ -65,6 +68,18 @@ 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_;
#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);
#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);

View File

@ -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

View File

@ -13,3 +13,6 @@ MulticastFlood = false
MulticastToUnicast = true
NeighborSuppression = true
Learning = false
Priority = 23
UseBPDU = true
AllowPortToBeRoot=true

View File

@ -3,3 +3,6 @@ Name=test1
[Network]
Bridge=bridge99
[Bridge]
Priority=0

View File

@ -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')
@ -2007,18 +2024,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)