2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2017-04-25 09:32:59 +02:00
|
|
|
#include <linux/icmpv6.h>
|
2020-08-13 11:55:06 +02:00
|
|
|
#include <linux/ipv6_route.h>
|
2017-04-25 09:32:59 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
#include "netlink-util.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-ipv4ll.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-manager.h"
|
2020-10-02 03:55:06 +02:00
|
|
|
#include "networkd-network.h"
|
2020-10-02 02:27:28 +02:00
|
|
|
#include "networkd-nexthop.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "networkd-route.h"
|
2020-10-02 02:27:28 +02:00
|
|
|
#include "networkd-routing-policy-rule.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2020-01-11 11:21:01 +01:00
|
|
|
#include "socket-netlink.h"
|
2019-07-07 01:43:33 +02:00
|
|
|
#include "string-table.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2020-07-16 07:48:08 +02:00
|
|
|
#include "strv.h"
|
2019-07-07 14:50:05 +02:00
|
|
|
#include "strxcpyx.h"
|
2016-08-21 15:06:28 +02:00
|
|
|
#include "sysctl-util.h"
|
2020-02-26 07:42:32 +01:00
|
|
|
#include "vrf.h"
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2016-08-21 15:06:28 +02:00
|
|
|
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
|
|
|
|
|
2020-10-02 08:48:01 +02:00
|
|
|
static uint32_t link_get_vrf_table(Link *link) {
|
|
|
|
return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t link_get_dhcp_route_table(Link *link) {
|
|
|
|
/* When the interface is part of an VRF use the VRFs routing table, unless
|
|
|
|
* another table is explicitly specified. */
|
|
|
|
if (link->network->dhcp_route_table_set)
|
|
|
|
return link->network->dhcp_route_table;
|
|
|
|
return link_get_vrf_table(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
|
|
|
|
if (link->network->ipv6_accept_ra_route_table_set)
|
|
|
|
return link->network->ipv6_accept_ra_route_table;
|
|
|
|
return link_get_vrf_table(link);
|
|
|
|
}
|
|
|
|
|
2020-10-02 03:16:25 +02:00
|
|
|
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_PRIVATE_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);
|
|
|
|
|
|
|
|
#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
|
|
|
|
static 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);
|
|
|
|
|
|
|
|
#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) {
|
|
|
|
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_FROM_STRING(route_protocol, int);
|
|
|
|
|
|
|
|
static const char * const route_protocol_full_table[] = {
|
|
|
|
[RTPROT_REDIRECT] = "redirect",
|
|
|
|
[RTPROT_KERNEL] = "kernel",
|
|
|
|
[RTPROT_BOOT] = "boot",
|
|
|
|
[RTPROT_STATIC] = "static",
|
|
|
|
[RTPROT_GATED] = "gated",
|
|
|
|
[RTPROT_RA] = "ra",
|
|
|
|
[RTPROT_MRT] = "mrt",
|
|
|
|
[RTPROT_ZEBRA] = "zebra",
|
|
|
|
[RTPROT_BIRD] = "bird",
|
|
|
|
[RTPROT_DNROUTED] = "dnrouted",
|
|
|
|
[RTPROT_XORP] = "xorp",
|
|
|
|
[RTPROT_NTK] = "ntk",
|
|
|
|
[RTPROT_DHCP] = "dhcp",
|
|
|
|
[RTPROT_MROUTED] = "mrouted",
|
|
|
|
[RTPROT_BABEL] = "babel",
|
|
|
|
[RTPROT_BGP] = "bgp",
|
|
|
|
[RTPROT_ISIS] = "isis",
|
|
|
|
[RTPROT_OSPF] = "ospf",
|
|
|
|
[RTPROT_RIP] = "rip",
|
|
|
|
[RTPROT_EIGRP] = "eigrp",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
|
|
|
|
|
|
|
|
#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
|
|
|
|
static const char *format_route_protocol(int protocol, char *buf, size_t size) {
|
|
|
|
const char *s;
|
|
|
|
char *p = buf;
|
|
|
|
|
|
|
|
s = route_protocol_full_to_string(protocol);
|
|
|
|
if (s)
|
|
|
|
strpcpy(&p, size, s);
|
|
|
|
else
|
|
|
|
strpcpyf(&p, size, "%d", protocol);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:06:28 +02:00
|
|
|
static unsigned routes_max(void) {
|
|
|
|
static thread_local unsigned cached = 0;
|
|
|
|
|
|
|
|
_cleanup_free_ char *s4 = NULL, *s6 = NULL;
|
|
|
|
unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
|
|
|
|
|
|
|
if (cached > 0)
|
|
|
|
return cached;
|
|
|
|
|
|
|
|
if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) {
|
|
|
|
truncate_nl(s4);
|
|
|
|
if (safe_atou(s4, &val4) >= 0 &&
|
|
|
|
val4 == 2147483647U)
|
|
|
|
/* This is the default "no limit" value in the kernel */
|
|
|
|
val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) {
|
|
|
|
truncate_nl(s6);
|
|
|
|
(void) safe_atou(s6, &val6);
|
|
|
|
}
|
|
|
|
|
|
|
|
cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
|
|
|
|
MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
|
|
|
|
return cached;
|
|
|
|
}
|
2016-06-03 19:14:12 +02:00
|
|
|
|
2015-10-09 23:43:52 +02:00
|
|
|
int route_new(Route **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(route_freep) Route *route = NULL;
|
2015-09-21 15:53:40 +02:00
|
|
|
|
2018-11-12 06:55:52 +01:00
|
|
|
route = new(Route, 1);
|
2015-09-21 15:53:40 +02:00
|
|
|
if (!route)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-12 06:55:52 +01:00
|
|
|
*route = (Route) {
|
|
|
|
.family = AF_UNSPEC,
|
|
|
|
.scope = RT_SCOPE_UNIVERSE,
|
|
|
|
.protocol = RTPROT_UNSPEC,
|
|
|
|
.type = RTN_UNICAST,
|
|
|
|
.table = RT_TABLE_MAIN,
|
|
|
|
.lifetime = USEC_INFINITY,
|
|
|
|
.quickack = -1,
|
2019-05-13 13:15:33 +02:00
|
|
|
.fast_open_no_cookie = -1,
|
2019-02-28 02:10:38 +01:00
|
|
|
.gateway_onlink = -1,
|
2019-05-16 11:49:08 +02:00
|
|
|
.ttl_propagate = -1,
|
2018-11-12 06:55:52 +01:00
|
|
|
};
|
2015-09-21 15:53:40 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(route);
|
2015-09-21 15:53:40 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-01 05:19:53 +01:00
|
|
|
static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
|
|
|
_cleanup_(route_freep) Route *route = NULL;
|
2015-09-21 15:53:40 +02:00
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2016-06-03 19:14:12 +02:00
|
|
|
assert(network);
|
|
|
|
assert(ret);
|
2020-10-02 03:41:55 +02:00
|
|
|
assert(filename);
|
|
|
|
assert(section_line > 0);
|
2017-02-15 05:30:35 +01:00
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
r = network_config_section_new(filename, section_line, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
route = hashmap_get(network->routes_by_section, n);
|
|
|
|
if (route) {
|
|
|
|
*ret = TAKE_PTR(route);
|
|
|
|
return 0;
|
2013-11-19 16:54:42 +01:00
|
|
|
}
|
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
if (hashmap_size(network->routes_by_section) >= routes_max())
|
2016-06-03 19:14:12 +02:00
|
|
|
return -E2BIG;
|
|
|
|
|
2015-10-09 23:43:52 +02:00
|
|
|
r = route_new(&route);
|
2015-09-21 15:53:40 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-28 20:00:47 +01:00
|
|
|
|
2015-10-09 23:43:52 +02:00
|
|
|
route->protocol = RTPROT_STATIC;
|
2018-11-12 06:57:04 +01:00
|
|
|
route->network = network;
|
2020-10-02 03:41:55 +02:00
|
|
|
route->section = TAKE_PTR(n);
|
2016-04-25 09:07:10 +02:00
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-11-12 07:24:11 +01:00
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
r = hashmap_put(network->routes_by_section, route->section, route);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(route);
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 02:31:29 +02:00
|
|
|
Route *route_free(Route *route) {
|
2013-10-17 03:18:36 +02:00
|
|
|
if (!route)
|
2020-10-02 02:31:29 +02:00
|
|
|
return NULL;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-01-01 15:16:10 +01:00
|
|
|
if (route->network) {
|
2020-10-02 03:41:55 +02:00
|
|
|
assert(route->section);
|
|
|
|
hashmap_remove(route->network->routes_by_section, route->section);
|
2014-01-01 15:16:10 +01:00
|
|
|
}
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2017-02-17 15:26:10 +01:00
|
|
|
network_config_section_free(route->section);
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
if (route->link) {
|
2020-08-14 10:45:44 +02:00
|
|
|
NDiscRoute *n;
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
set_remove(route->link->routes, route);
|
|
|
|
set_remove(route->link->routes_foreign, route);
|
2020-07-21 16:06:51 +02:00
|
|
|
set_remove(route->link->dhcp_routes, route);
|
|
|
|
set_remove(route->link->dhcp_routes_old, route);
|
2020-07-22 20:13:42 +02:00
|
|
|
set_remove(route->link->dhcp6_routes, route);
|
|
|
|
set_remove(route->link->dhcp6_routes_old, route);
|
|
|
|
set_remove(route->link->dhcp6_pd_routes, route);
|
|
|
|
set_remove(route->link->dhcp6_pd_routes_old, route);
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(n, route->link->ndisc_routes)
|
2020-08-14 10:45:44 +02:00
|
|
|
if (n->route == route)
|
|
|
|
free(set_remove(route->link->ndisc_routes, n));
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (route->manager) {
|
|
|
|
set_remove(route->manager->routes, route);
|
|
|
|
set_remove(route->manager->routes_foreign, route);
|
|
|
|
}
|
|
|
|
|
2019-11-28 16:36:02 +01:00
|
|
|
ordered_set_free_free(route->multipath_routes);
|
|
|
|
|
2015-10-26 12:29:37 +01:00
|
|
|
sd_event_source_unref(route->expire);
|
|
|
|
|
2020-10-02 02:31:29 +02:00
|
|
|
return mfree(route);
|
2013-10-17 03:18:36 +02:00
|
|
|
}
|
|
|
|
|
2020-09-04 03:56:03 +02:00
|
|
|
void route_hash_func(const Route *route, struct siphash *state) {
|
2015-10-03 18:40:28 +02:00
|
|
|
assert(route);
|
|
|
|
|
|
|
|
siphash24_compress(&route->family, sizeof(route->family), state);
|
|
|
|
|
2019-07-16 18:47:52 +02:00
|
|
|
switch (route->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
|
|
|
siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
|
2019-09-17 19:11:31 +02:00
|
|
|
siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
|
|
|
|
|
2019-07-16 18:47:52 +02:00
|
|
|
siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
|
2019-09-17 19:11:31 +02:00
|
|
|
siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
|
|
|
|
|
|
|
|
siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
|
|
|
|
|
2019-07-16 18:47:52 +02:00
|
|
|
siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
|
|
|
|
|
|
|
|
siphash24_compress(&route->tos, sizeof(route->tos), state);
|
|
|
|
siphash24_compress(&route->priority, sizeof(route->priority), state);
|
|
|
|
siphash24_compress(&route->table, sizeof(route->table), state);
|
|
|
|
siphash24_compress(&route->protocol, sizeof(route->protocol), state);
|
|
|
|
siphash24_compress(&route->scope, sizeof(route->scope), state);
|
|
|
|
siphash24_compress(&route->type, sizeof(route->type), state);
|
2019-09-17 19:11:31 +02:00
|
|
|
|
2019-09-09 17:18:05 +02:00
|
|
|
siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
|
|
|
|
siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
|
2019-07-16 18:47:52 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* treat any other address family as AF_UNSPEC */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 03:56:03 +02:00
|
|
|
int route_compare_func(const Route *a, const Route *b) {
|
2019-07-16 18:47:52 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
r = CMP(a->family, b->family);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
switch (a->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
|
|
|
r = CMP(a->dst_prefixlen, b->dst_prefixlen);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-16 18:47:52 +02:00
|
|
|
r = CMP(a->src_prefixlen, b->src_prefixlen);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->tos, b->tos);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->priority, b->priority);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->table, b->table);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->protocol, b->protocol);
|
2019-09-09 17:18:05 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->scope, b->scope);
|
2019-09-09 17:18:05 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->type, b->type);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->initcwnd, b->initcwnd);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = CMP(a->initrwnd, b->initrwnd);
|
2019-07-16 18:47:52 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
return 0;
|
2019-07-16 18:47:52 +02:00
|
|
|
default:
|
|
|
|
/* treat any other address family as AF_UNSPEC */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
2019-09-09 17:17:28 +02:00
|
|
|
route_hash_ops,
|
2019-07-16 18:47:52 +02:00
|
|
|
Route,
|
2019-09-09 17:17:28 +02:00
|
|
|
route_hash_func,
|
|
|
|
route_compare_func,
|
2019-07-16 18:47:52 +02:00
|
|
|
route_free);
|
|
|
|
|
2020-10-02 03:16:25 +02:00
|
|
|
static bool route_equal(Route *r1, Route *r2) {
|
2018-11-06 13:28:12 +01:00
|
|
|
if (r1 == r2)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!r1 || !r2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return route_compare_func(r1, r2) == 0;
|
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
static int route_get(Manager *manager, Link *link, Route *in, Route **ret) {
|
2019-09-09 17:16:41 +02:00
|
|
|
Route *existing;
|
2016-06-03 19:51:48 +02:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
assert(manager || link);
|
2019-09-09 17:16:41 +02:00
|
|
|
assert(in);
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (link) {
|
|
|
|
existing = set_get(link->routes, in);
|
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
|
|
|
return 1;
|
|
|
|
}
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
existing = set_get(link->routes_foreign, in);
|
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
existing = set_get(manager->routes, in);
|
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
existing = set_get(manager->routes_foreign, in);
|
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
|
|
|
return 0;
|
|
|
|
}
|
2016-06-03 19:51:48 +02:00
|
|
|
}
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2016-06-03 19:51:48 +02:00
|
|
|
return -ENOENT;
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
static int route_add_internal(Manager *manager, Link *link, Set **routes, Route *in, Route **ret) {
|
2016-06-03 19:54:35 +02:00
|
|
|
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(route_freep) Route *route = NULL;
|
2015-10-25 14:46:21 +01:00
|
|
|
int r;
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
assert(manager || link);
|
2015-10-25 14:46:21 +01:00
|
|
|
assert(routes);
|
2019-09-09 17:16:41 +02:00
|
|
|
assert(in);
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
r = route_new(&route);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
route->family = in->family;
|
|
|
|
route->src = in->src;
|
|
|
|
route->src_prefixlen = in->src_prefixlen;
|
|
|
|
route->dst = in->dst;
|
|
|
|
route->dst_prefixlen = in->dst_prefixlen;
|
|
|
|
route->gw = in->gw;
|
|
|
|
route->prefsrc = in->prefsrc;
|
|
|
|
route->scope = in->scope;
|
|
|
|
route->protocol = in->protocol;
|
|
|
|
route->type = in->type;
|
|
|
|
route->tos = in->tos;
|
|
|
|
route->priority = in->priority;
|
|
|
|
route->table = in->table;
|
|
|
|
route->initcwnd = in->initcwnd;
|
|
|
|
route->initrwnd = in->initrwnd;
|
|
|
|
route->lifetime = in->lifetime;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(routes, &route_hash_ops, route);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-08-11 01:56:37 +02:00
|
|
|
if (r == 0)
|
|
|
|
return -EEXIST;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
route->link = link;
|
2020-10-07 02:41:52 +02:00
|
|
|
route->manager = manager;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
*ret = route;
|
|
|
|
|
|
|
|
route = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
static int route_add_foreign(Manager *manager, Link *link, Route *in, Route **ret) {
|
|
|
|
assert(manager || link);
|
|
|
|
return route_add_internal(manager, link, link ? &link->routes_foreign : &manager->routes_foreign, in, ret);
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
static int route_add(Manager *manager, Link *link, Route *in, Route **ret) {
|
2015-10-25 14:46:21 +01:00
|
|
|
Route *route;
|
|
|
|
int r;
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
assert(manager || link);
|
|
|
|
assert(in);
|
|
|
|
|
|
|
|
r = route_get(manager, link, in, &route);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r == -ENOENT) {
|
|
|
|
/* Route does not exist, create a new one */
|
2020-10-07 02:41:52 +02:00
|
|
|
r = route_add_internal(manager, link, link ? &link->routes : &manager->routes, in, &route);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r == 0) {
|
|
|
|
/* Take over a foreign route */
|
2020-10-07 02:41:52 +02:00
|
|
|
if (link) {
|
|
|
|
r = set_ensure_put(&link->routes, &route_hash_ops, route);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
set_remove(link->routes_foreign, route);
|
|
|
|
} else {
|
|
|
|
r = set_ensure_put(&manager->routes, &route_hash_ops, route);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
set_remove(manager->routes_foreign, route);
|
|
|
|
}
|
2015-10-25 14:46:21 +01:00
|
|
|
} else if (r == 1) {
|
|
|
|
/* Route exists, do nothing */
|
|
|
|
;
|
|
|
|
} else
|
|
|
|
return r;
|
|
|
|
|
2016-08-16 11:07:42 +02:00
|
|
|
if (ret)
|
|
|
|
*ret = route;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2018-11-28 21:22:42 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
/* Note that link may be NULL. */
|
|
|
|
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2018-11-28 21:22:42 +01:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0 && r != -ESRCH)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
|
2018-11-28 21:22:42 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
int route_remove(
|
|
|
|
Route *route,
|
|
|
|
Manager *manager,
|
|
|
|
Link *link,
|
|
|
|
link_netlink_message_handler_t callback) {
|
2018-05-11 05:36:15 +02:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-02-28 16:10:20 +01:00
|
|
|
int r;
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
assert(link || manager);
|
2017-10-04 16:01:32 +02:00
|
|
|
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (!manager)
|
|
|
|
manager = link->manager;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_route(manager->rtnl, &req,
|
2014-07-22 23:54:47 +02:00
|
|
|
RTM_DELROUTE, route->family,
|
|
|
|
route->protocol);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2019-07-07 14:50:05 +02:00
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
|
2019-07-09 17:18:53 +02:00
|
|
|
char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
|
2019-07-07 14:50:05 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-07-09 17:18:53 +02:00
|
|
|
log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
2019-07-07 14:50:05 +02:00
|
|
|
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)),
|
2019-07-09 17:18:53 +02:00
|
|
|
format_route_protocol(route->protocol, protocol, sizeof(protocol)),
|
2019-07-07 14:50:05 +02:00
|
|
|
strna(route_type_to_string(route->type)));
|
|
|
|
}
|
|
|
|
|
2019-02-03 00:09:13 +01:00
|
|
|
if (in_addr_is_null(route->family, &route->gw) == 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (route->dst_prefixlen) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
|
|
|
|
2014-12-04 15:52:21 +01:00
|
|
|
if (route->src_prefixlen) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
|
2014-12-04 15:52:21 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
|
2014-12-04 15:52:21 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set source prefix length: %m");
|
2014-12-04 15:52:21 +01:00
|
|
|
}
|
|
|
|
|
2019-02-03 00:09:13 +01:00
|
|
|
if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
|
2014-09-05 11:56:02 +02:00
|
|
|
}
|
|
|
|
|
2014-02-28 16:10:20 +01:00
|
|
|
r = sd_rtnl_message_route_set_scope(req, route->scope);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set scope: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2015-10-26 17:04:57 +01:00
|
|
|
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2018-10-13 08:01:47 +02:00
|
|
|
if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
|
2017-09-19 16:28:26 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
|
2017-09-19 16:28:26 +02:00
|
|
|
}
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req,
|
|
|
|
callback ?: route_remove_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (link)
|
|
|
|
link_ref(link);
|
2014-07-03 09:43:31 +02:00
|
|
|
|
2014-02-28 16:10:20 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 02:38:31 +02:00
|
|
|
static bool link_is_static_route_configured(Link *link, Route *route) {
|
|
|
|
Route *net_route;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(route);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
HASHMAP_FOREACH(net_route, link->network->routes_by_section)
|
2020-10-02 02:38:31 +02:00
|
|
|
if (route_equal(net_route, route))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int link_drop_foreign_routes(Link *link) {
|
|
|
|
Route *route;
|
|
|
|
int k, r = 0;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
SET_FOREACH(route, link->routes_foreign) {
|
|
|
|
/* do not touch routes managed by the kernel */
|
|
|
|
if (route->protocol == RTPROT_KERNEL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* do not touch multicast route added by kernel */
|
|
|
|
/* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
|
|
|
|
* https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
|
|
|
|
if (route->protocol == RTPROT_BOOT &&
|
|
|
|
route->family == AF_INET6 &&
|
|
|
|
route->dst_prefixlen == 8 &&
|
|
|
|
in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (route->protocol == RTPROT_STATIC && link->network &&
|
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (route->protocol == RTPROT_DHCP && link->network &&
|
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link_is_static_route_configured(link, route))
|
2020-10-07 02:41:52 +02:00
|
|
|
k = route_add(NULL, link, route, NULL);
|
2020-10-02 02:38:31 +02:00
|
|
|
else
|
2020-10-07 02:41:52 +02:00
|
|
|
k = route_remove(route, NULL, link, NULL);
|
2020-10-02 02:38:31 +02:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-10-02 02:40:31 +02:00
|
|
|
int link_drop_routes(Link *link) {
|
|
|
|
Route *route;
|
|
|
|
int k, r = 0;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
SET_FOREACH(route, link->routes) {
|
|
|
|
/* do not touch routes managed by the kernel */
|
|
|
|
if (route->protocol == RTPROT_KERNEL)
|
|
|
|
continue;
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
k = route_remove(route, NULL, link, NULL);
|
2020-10-02 02:40:31 +02:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-10-02 03:16:25 +02:00
|
|
|
static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
2015-10-26 12:29:37 +01:00
|
|
|
Route *route = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(route);
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
r = route_remove(route, route->manager, route->link, NULL);
|
2015-10-26 12:29:37 +01:00
|
|
|
if (r < 0)
|
2020-01-07 04:53:19 +01:00
|
|
|
log_link_warning_errno(route->link, r, "Could not remove route: %m");
|
2016-08-18 09:46:21 +02:00
|
|
|
else
|
2016-05-18 03:36:43 +02:00
|
|
|
route_free(route);
|
2015-10-26 12:29:37 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-11-28 16:36:02 +01:00
|
|
|
static int append_nexthop_one(Route *route, MultipathRoute *m, struct rtattr **rta, size_t offset) {
|
|
|
|
struct rtnexthop *rtnh;
|
|
|
|
struct rtattr *new_rta;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(route);
|
|
|
|
assert(m);
|
|
|
|
assert(rta);
|
|
|
|
assert(*rta);
|
|
|
|
|
|
|
|
new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
|
|
|
|
if (!new_rta)
|
|
|
|
return -ENOMEM;
|
|
|
|
*rta = new_rta;
|
|
|
|
|
|
|
|
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
|
|
|
*rtnh = (struct rtnexthop) {
|
|
|
|
.rtnh_len = sizeof(*rtnh),
|
|
|
|
.rtnh_ifindex = m->ifindex,
|
|
|
|
.rtnh_hops = m->weight > 0 ? m->weight - 1 : 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
(*rta)->rta_len += sizeof(struct rtnexthop);
|
|
|
|
|
|
|
|
if (route->family == m->gateway.family) {
|
|
|
|
r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
|
|
|
|
if (r < 0)
|
|
|
|
goto clear;
|
|
|
|
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
|
|
|
rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
|
|
|
|
} else {
|
|
|
|
r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
|
|
|
|
if (r < 0)
|
|
|
|
goto clear;
|
|
|
|
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
|
|
|
rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
clear:
|
|
|
|
(*rta)->rta_len -= sizeof(struct rtnexthop);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int append_nexthops(Route *route, sd_netlink_message *req) {
|
|
|
|
_cleanup_free_ struct rtattr *rta = NULL;
|
|
|
|
struct rtnexthop *rtnh;
|
|
|
|
MultipathRoute *m;
|
|
|
|
size_t offset;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (ordered_set_isempty(route->multipath_routes))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rta = new(struct rtattr, 1);
|
|
|
|
if (!rta)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*rta = (struct rtattr) {
|
|
|
|
.rta_type = RTA_MULTIPATH,
|
|
|
|
.rta_len = RTA_LENGTH(0),
|
|
|
|
};
|
|
|
|
offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
2019-11-28 16:36:02 +01:00
|
|
|
r = append_nexthop_one(route, m, &rta, offset);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
|
|
|
|
offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-03 19:51:48 +02:00
|
|
|
int route_configure(
|
|
|
|
Route *route,
|
|
|
|
Link *link,
|
2020-07-22 02:41:30 +02:00
|
|
|
link_netlink_message_handler_t callback,
|
|
|
|
Route **ret) {
|
2016-06-03 19:51:48 +02:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
2013-10-17 03:18:36 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
2013-11-14 16:22:51 +01:00
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(link->ifindex > 0);
|
2017-10-04 16:01:32 +02:00
|
|
|
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
2018-11-28 21:29:09 +01:00
|
|
|
assert(callback);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (route_get(link->manager, link, route, NULL) <= 0 &&
|
2016-08-21 15:06:28 +02:00
|
|
|
set_size(link->routes) >= routes_max())
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
|
|
|
"Too many routes are configured, refusing: %m");
|
2016-06-03 19:51:48 +02:00
|
|
|
|
2019-02-11 13:28:13 +01:00
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
|
2019-07-09 17:18:53 +02:00
|
|
|
char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
|
2019-02-11 13:28:13 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-07-09 17:18:53 +02:00
|
|
|
log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
2019-07-07 14:50:05 +02:00
|
|
|
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)),
|
2019-07-09 17:18:53 +02:00
|
|
|
format_route_protocol(route->protocol, protocol, sizeof(protocol)),
|
2019-07-07 14:50:05 +02:00
|
|
|
strna(route_type_to_string(route->type)));
|
2019-02-11 13:28:13 +01:00
|
|
|
}
|
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
|
2014-07-22 23:54:47 +02:00
|
|
|
RTM_NEWROUTE, route->family,
|
|
|
|
route->protocol);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-02-03 00:09:13 +01:00
|
|
|
if (in_addr_is_null(route->family, &route->gw) == 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
|
2016-05-03 19:48:21 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_route_set_family(req, route->family);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set route family: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
}
|
|
|
|
|
2019-08-29 01:13:15 +02:00
|
|
|
if (route->dst_prefixlen > 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2013-12-07 23:03:19 +01:00
|
|
|
r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
|
2013-12-07 21:18:44 +01:00
|
|
|
}
|
|
|
|
|
2019-08-29 01:13:15 +02:00
|
|
|
if (route->src_prefixlen > 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
|
2014-12-04 15:52:21 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
|
2014-12-04 15:52:21 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set source prefix length: %m");
|
2014-12-04 15:52:21 +01:00
|
|
|
}
|
|
|
|
|
2019-02-03 00:09:13 +01:00
|
|
|
if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
|
2019-02-03 01:47:25 +01:00
|
|
|
r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
|
2014-09-05 11:56:02 +02:00
|
|
|
}
|
|
|
|
|
2014-02-28 16:10:20 +01:00
|
|
|
r = sd_rtnl_message_route_set_scope(req, route->scope);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set scope: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2019-02-28 02:10:38 +01:00
|
|
|
if (route->gateway_onlink >= 0)
|
|
|
|
SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
|
|
|
|
|
networkd: ndisc - handle router advertisement in userspace
Router Discovery is a core part of IPv6, which by default is handled by the kernel.
However, the kernel implementation is meant as a fall-back, and to fully support
the protocol a userspace implementation is desired.
The protocol essentially listens for Router Advertisement packets from routers
on the local link and use these to configure the client automatically. The four
main pieces of information are: what kind (if any) of DHCPv6 configuration should
be performed; a default gateway; the prefixes that should be considered to be on
the local link; and the prefixes with which we can preform SLAAC in order to pick
a global IPv6 address.
A lot of additional information is also available, which we do not yet fully
support, but which will eventually allow us to avoid the need for DHCPv6 in the
common case.
Short-term, the reason for wanting this is in userspace was the desire to fully
track all the addresses on links we manage, and that is not possible for addresses
managed by the kernel (as the kernel does not expose to us the fact that it
manages these addresses). Moreover, we would like to support stable privacy
addresses, which will soon be mandated and the legacy MAC-based global addresses
deprecated, to do this well we need to handle the generation in userspace. Lastly,
more long-term we wish to support more RA options than what the kernel exposes.
2015-11-03 13:02:16 +01:00
|
|
|
r = sd_rtnl_message_route_set_flags(req, route->flags);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set flags: %m");
|
2016-05-03 19:48:21 +02:00
|
|
|
|
2016-08-18 09:54:12 +02:00
|
|
|
if (route->table != RT_TABLE_MAIN) {
|
2016-05-03 19:48:21 +02:00
|
|
|
if (route->table < 256) {
|
|
|
|
r = sd_rtnl_message_route_set_table(req, route->table);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set route table: %m");
|
2016-05-03 19:48:21 +02:00
|
|
|
} else {
|
|
|
|
r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set route table: %m");
|
2016-05-03 19:48:21 +02:00
|
|
|
|
2016-05-06 06:19:49 +02:00
|
|
|
/* Table attribute to allow more than 256. */
|
2016-05-03 19:48:21 +02:00
|
|
|
r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
|
2016-05-03 19:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
networkd: ndisc - handle router advertisement in userspace
Router Discovery is a core part of IPv6, which by default is handled by the kernel.
However, the kernel implementation is meant as a fall-back, and to fully support
the protocol a userspace implementation is desired.
The protocol essentially listens for Router Advertisement packets from routers
on the local link and use these to configure the client automatically. The four
main pieces of information are: what kind (if any) of DHCPv6 configuration should
be performed; a default gateway; the prefixes that should be considered to be on
the local link; and the prefixes with which we can preform SLAAC in order to pick
a global IPv6 address.
A lot of additional information is also available, which we do not yet fully
support, but which will eventually allow us to avoid the need for DHCPv6 in the
common case.
Short-term, the reason for wanting this is in userspace was the desire to fully
track all the addresses on links we manage, and that is not possible for addresses
managed by the kernel (as the kernel does not expose to us the fact that it
manages these addresses). Moreover, we would like to support stable privacy
addresses, which will soon be mandated and the legacy MAC-based global addresses
deprecated, to do this well we need to handle the generation in userspace. Lastly,
more long-term we wish to support more RA options than what the kernel exposes.
2015-11-03 13:02:16 +01:00
|
|
|
|
2015-10-26 17:04:57 +01:00
|
|
|
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
networkd: ndisc - handle router advertisement in userspace
Router Discovery is a core part of IPv6, which by default is handled by the kernel.
However, the kernel implementation is meant as a fall-back, and to fully support
the protocol a userspace implementation is desired.
The protocol essentially listens for Router Advertisement packets from routers
on the local link and use these to configure the client automatically. The four
main pieces of information are: what kind (if any) of DHCPv6 configuration should
be performed; a default gateway; the prefixes that should be considered to be on
the local link; and the prefixes with which we can preform SLAAC in order to pick
a global IPv6 address.
A lot of additional information is also available, which we do not yet fully
support, but which will eventually allow us to avoid the need for DHCPv6 in the
common case.
Short-term, the reason for wanting this is in userspace was the desire to fully
track all the addresses on links we manage, and that is not possible for addresses
managed by the kernel (as the kernel does not expose to us the fact that it
manages these addresses). Moreover, we would like to support stable privacy
addresses, which will soon be mandated and the legacy MAC-based global addresses
deprecated, to do this well we need to handle the generation in userspace. Lastly,
more long-term we wish to support more RA options than what the kernel exposes.
2015-11-03 13:02:16 +01:00
|
|
|
r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
|
networkd: ndisc - handle router advertisement in userspace
Router Discovery is a core part of IPv6, which by default is handled by the kernel.
However, the kernel implementation is meant as a fall-back, and to fully support
the protocol a userspace implementation is desired.
The protocol essentially listens for Router Advertisement packets from routers
on the local link and use these to configure the client automatically. The four
main pieces of information are: what kind (if any) of DHCPv6 configuration should
be performed; a default gateway; the prefixes that should be considered to be on
the local link; and the prefixes with which we can preform SLAAC in order to pick
a global IPv6 address.
A lot of additional information is also available, which we do not yet fully
support, but which will eventually allow us to avoid the need for DHCPv6 in the
common case.
Short-term, the reason for wanting this is in userspace was the desire to fully
track all the addresses on links we manage, and that is not possible for addresses
managed by the kernel (as the kernel does not expose to us the fact that it
manages these addresses). Moreover, we would like to support stable privacy
addresses, which will soon be mandated and the legacy MAC-based global addresses
deprecated, to do this well we need to handle the generation in userspace. Lastly,
more long-term we wish to support more RA options than what the kernel exposes.
2015-11-03 13:02:16 +01:00
|
|
|
|
2018-02-26 15:33:16 +01:00
|
|
|
if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
|
|
|
|
r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
|
|
|
|
DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
|
2018-02-26 15:33:16 +01:00
|
|
|
}
|
|
|
|
|
2017-09-19 16:28:26 +02:00
|
|
|
r = sd_rtnl_message_route_set_type(req, route->type);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not set route type: %m");
|
2017-09-19 16:28:26 +02:00
|
|
|
|
2018-10-13 08:01:47 +02:00
|
|
|
if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
|
2017-09-19 16:28:26 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
|
2017-09-19 16:28:26 +02:00
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-16 11:49:08 +02:00
|
|
|
if (route->ttl_propagate >= 0) {
|
|
|
|
r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
|
|
|
|
}
|
|
|
|
|
2016-11-23 22:32:19 +01:00
|
|
|
r = sd_netlink_message_open_container(req, RTA_METRICS);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
|
2016-11-23 22:32:19 +01:00
|
|
|
|
|
|
|
if (route->mtu > 0) {
|
|
|
|
r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
|
2016-11-23 22:32:19 +01:00
|
|
|
}
|
|
|
|
|
2018-01-02 10:20:15 +01:00
|
|
|
if (route->initcwnd > 0) {
|
2017-12-29 15:18:05 +01:00
|
|
|
r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
|
2017-12-29 15:18:05 +01:00
|
|
|
}
|
|
|
|
|
2018-01-02 10:20:15 +01:00
|
|
|
if (route->initrwnd > 0) {
|
2017-12-29 15:18:05 +01:00
|
|
|
r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
|
2017-12-29 15:18:05 +01:00
|
|
|
}
|
|
|
|
|
2019-05-14 04:39:54 +02:00
|
|
|
if (route->quickack >= 0) {
|
2018-01-20 00:49:15 +01:00
|
|
|
r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
|
2018-01-20 00:49:15 +01:00
|
|
|
}
|
|
|
|
|
2019-05-13 13:15:33 +02:00
|
|
|
if (route->fast_open_no_cookie >= 0) {
|
|
|
|
r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
|
|
|
|
}
|
|
|
|
|
2016-11-23 22:32:19 +01:00
|
|
|
r = sd_netlink_message_close_container(req);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
|
2016-11-23 22:32:19 +01:00
|
|
|
|
2019-11-28 16:36:02 +01:00
|
|
|
r = append_nexthops(route, req);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
|
|
|
|
link_netlink_destroy_callback, link);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-07-03 09:43:31 +02:00
|
|
|
link_ref(link);
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
if (IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW) || !ordered_set_isempty(route->multipath_routes))
|
|
|
|
r = route_add(link->manager, NULL, route, &route);
|
|
|
|
else
|
|
|
|
r = route_add(NULL, link, route, &route);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not add route: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2015-10-26 12:29:37 +01:00
|
|
|
/* TODO: drop expiration handling once it can be pushed into the kernel */
|
2018-02-26 15:33:16 +01:00
|
|
|
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
2015-10-26 12:29:37 +01:00
|
|
|
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
|
|
|
|
route->lifetime, 0, route_expire_handler, route);
|
|
|
|
if (r < 0)
|
2019-03-11 06:30:45 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
|
2015-10-26 12:29:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sd_event_source_unref(route->expire);
|
2018-04-05 07:26:26 +02:00
|
|
|
route->expire = TAKE_PTR(expire);
|
2015-10-26 12:29:37 +01:00
|
|
|
|
2020-07-22 02:41:30 +02:00
|
|
|
if (ret)
|
|
|
|
*ret = route;
|
|
|
|
|
2019-06-11 16:26:11 +02:00
|
|
|
return 1;
|
2013-10-17 03:18:36 +02:00
|
|
|
}
|
|
|
|
|
2020-10-02 02:27:28 +02:00
|
|
|
static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->route_messages > 0);
|
|
|
|
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
|
|
|
|
LINK_STATE_FAILED, LINK_STATE_LINGER));
|
|
|
|
|
|
|
|
link->route_messages--;
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0 && r != -EEXIST) {
|
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set route");
|
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->route_messages == 0) {
|
|
|
|
log_link_debug(link, "Routes set");
|
|
|
|
link->static_routes_configured = true;
|
|
|
|
link_set_nexthop(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int link_set_routes(Link *link) {
|
|
|
|
enum {
|
|
|
|
PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
|
|
|
|
PHASE_GATEWAY, /* Second phase: Routes with a gateway */
|
|
|
|
_PHASE_MAX
|
|
|
|
} phase;
|
|
|
|
Route *rt;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->state != _LINK_STATE_INVALID);
|
|
|
|
|
|
|
|
link->static_routes_configured = false;
|
|
|
|
|
|
|
|
if (!link->addresses_ready)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
|
|
|
|
/* During configuring addresses, the link lost its carrier. As networkd is dropping
|
|
|
|
* the addresses now, let's not configure the routes either. */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = link_set_routing_policy_rules(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
|
|
|
|
for (phase = 0; phase < _PHASE_MAX; phase++)
|
2020-10-02 03:41:55 +02:00
|
|
|
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
|
2020-10-02 02:27:28 +02:00
|
|
|
if (rt->gateway_from_dhcp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = route_configure(rt, link, route_handler, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set routes: %m");
|
|
|
|
if (r > 0)
|
|
|
|
link->route_messages++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->route_messages == 0) {
|
|
|
|
link->static_routes_configured = true;
|
|
|
|
link_set_nexthop(link);
|
|
|
|
} else {
|
|
|
|
log_link_debug(link, "Setting routes");
|
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 02:29:07 +02:00
|
|
|
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
|
|
|
_cleanup_(route_freep) Route *tmp = NULL;
|
|
|
|
Route *route = NULL;
|
|
|
|
Link *link = NULL;
|
|
|
|
uint32_t ifindex;
|
|
|
|
uint16_t type;
|
|
|
|
unsigned char table;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
|
|
|
|
log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
2020-10-07 02:41:52 +02:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2020-10-02 02:29:07 +02:00
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
|
|
|
|
return 0;
|
2020-10-07 02:41:52 +02:00
|
|
|
} else if (r >= 0) {
|
|
|
|
if (ifindex <= 0) {
|
|
|
|
log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-02 02:29:07 +02:00
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
r = link_get(m, ifindex, &link);
|
|
|
|
if (r < 0 || !link) {
|
|
|
|
/* 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 message for link (%d) we do not know about, ignoring", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-02 02:29:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = route_new(&tmp);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_family(message, &tmp->family);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning(link, "rtnl: received route message without family, ignoring");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
|
|
|
log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: received route message without route protocol: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (tmp->family) {
|
|
|
|
case AF_INET:
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received route message with unsupported address family");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
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, &tmp->src_prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
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, &tmp->scope);
|
|
|
|
if (r < 0) {
|
|
|
|
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, &tmp->tos);
|
|
|
|
if (r < 0) {
|
|
|
|
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, &tmp->type);
|
|
|
|
if (r < 0) {
|
|
|
|
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 message with invalid table, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
tmp->table = table;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_enter_container(message, RTA_METRICS);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r >= 0) {
|
|
|
|
r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_exit_container(message);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
(void) route_get(m, link, tmp, &route);
|
2020-10-02 02:29:07 +02:00
|
|
|
|
|
|
|
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(tmp->family, &tmp->dst)) {
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
|
|
|
|
(void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
|
|
|
|
}
|
|
|
|
if (!in_addr_is_null(tmp->family, &tmp->src))
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
|
|
|
|
if (!in_addr_is_null(tmp->family, &tmp->gw))
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
|
|
|
|
if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
|
|
|
|
|
|
|
|
log_link_debug(link,
|
|
|
|
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
2020-10-07 02:41:52 +02:00
|
|
|
(!route && !m->manage_foreign_routes) ? "Ignoring received foreign" :
|
2020-10-02 02:29:07 +02:00
|
|
|
type == RTM_DELROUTE ? "Forgetting" :
|
|
|
|
route ? "Received remembered" : "Remembering",
|
|
|
|
strna(buf_dst), strempty(buf_dst_prefixlen),
|
|
|
|
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
|
|
|
|
format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
|
|
|
|
format_route_table(tmp->table, buf_table, sizeof buf_table),
|
|
|
|
format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
|
|
|
|
strna(route_type_to_string(tmp->type)));
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWROUTE:
|
2020-10-07 02:41:52 +02:00
|
|
|
if (!route && m->manage_foreign_routes) {
|
2020-10-02 02:29:07 +02:00
|
|
|
/* A route appeared that we did not request */
|
2020-10-07 02:41:52 +02:00
|
|
|
r = route_add_foreign(m, link, tmp, &route);
|
2020-10-02 02:29:07 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELROUTE:
|
|
|
|
route_free(route);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received route message with invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-02 04:56:12 +02:00
|
|
|
int link_serialize_routes(Link *link, FILE *f) {
|
|
|
|
bool space = false;
|
|
|
|
Route *route;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(f);
|
|
|
|
|
|
|
|
fputs("ROUTES=", f);
|
|
|
|
SET_FOREACH(route, link->routes) {
|
|
|
|
_cleanup_free_ char *route_str = NULL;
|
|
|
|
|
|
|
|
if (in_addr_to_string(route->family, &route->dst, &route_str) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
|
|
|
|
space ? " " : "", route_str,
|
|
|
|
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
fputc('\n', f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 02:52:07 +02:00
|
|
|
int link_deserialize_routes(Link *link, const char *routes) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
for (const char *p = routes;; ) {
|
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
|
|
|
_cleanup_(route_freep) Route *tmp = NULL;
|
|
|
|
_cleanup_free_ char *route_str = NULL;
|
|
|
|
char *prefixlen_str;
|
|
|
|
Route *route;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &route_str, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_debug_errno(link, r, "Failed to parse ROUTES=: %m");
|
|
|
|
if (r == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
prefixlen_str = strchr(route_str, '/');
|
|
|
|
if (!prefixlen_str) {
|
|
|
|
log_link_debug(link, "Failed to parse route, ignoring: %s", route_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*prefixlen_str++ = '\0';
|
|
|
|
|
|
|
|
r = route_new(&tmp);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sscanf(prefixlen_str,
|
|
|
|
"%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
|
|
|
|
&tmp->dst_prefixlen,
|
|
|
|
&tmp->tos,
|
|
|
|
&tmp->priority,
|
|
|
|
&tmp->table,
|
|
|
|
&tmp->lifetime);
|
|
|
|
if (r != 5) {
|
|
|
|
log_link_debug(link,
|
|
|
|
"Failed to parse destination prefix length, tos, priority, table or expiration: %s",
|
|
|
|
prefixlen_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-10-07 02:41:52 +02:00
|
|
|
r = route_add(NULL, link, tmp, &route);
|
2020-10-02 02:52:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_debug_errno(link, r, "Failed to add route: %m");
|
|
|
|
|
|
|
|
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
|
|
|
r = sd_event_add_time(link->manager->event, &expire,
|
|
|
|
clock_boottime_or_monotonic(),
|
|
|
|
route->lifetime, 0, route_expire_handler, route);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_debug_errno(link, r, "Could not arm route expiration handler: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
sd_event_source_unref(route->expire);
|
|
|
|
route->expire = TAKE_PTR(expire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-05 02:51:57 +01:00
|
|
|
int network_add_ipv4ll_route(Network *network) {
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2020-10-02 03:41:55 +02:00
|
|
|
unsigned section_line;
|
2019-03-05 02:51:57 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
|
|
|
if (!network->ipv4ll_route)
|
|
|
|
return 0;
|
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
section_line = hashmap_find_free_section_line(network->routes_by_section);
|
|
|
|
|
2019-03-05 02:51:57 +01:00
|
|
|
/* IPv4LLRoute= is in [Network] section. */
|
2020-10-02 03:41:55 +02:00
|
|
|
r = route_new_static(network, network->filename, section_line, &n);
|
2019-03-05 02:51:57 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
n->family = AF_INET;
|
|
|
|
n->dst_prefixlen = 16;
|
|
|
|
n->scope = RT_SCOPE_LINK;
|
2019-07-07 02:40:17 +02:00
|
|
|
n->scope_set = true;
|
|
|
|
n->table_set = true;
|
2019-03-05 02:51:57 +01:00
|
|
|
n->priority = IPV4LL_ROUTE_METRIC;
|
|
|
|
n->protocol = RTPROT_STATIC;
|
|
|
|
|
|
|
|
TAKE_PTR(n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-14 09:43:14 +02:00
|
|
|
int network_add_default_route_on_device(Network *network) {
|
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2020-10-02 03:41:55 +02:00
|
|
|
unsigned section_line;
|
2019-05-14 09:43:14 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
|
|
|
if (!network->default_route_on_device)
|
|
|
|
return 0;
|
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
section_line = hashmap_find_free_section_line(network->routes_by_section);
|
|
|
|
|
2019-05-14 09:43:14 +02:00
|
|
|
/* DefaultRouteOnDevice= is in [Network] section. */
|
2020-10-02 03:41:55 +02:00
|
|
|
r = route_new_static(network, network->filename, section_line, &n);
|
2019-05-14 09:43:14 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
n->family = AF_INET;
|
2019-08-29 13:24:27 +02:00
|
|
|
n->scope = RT_SCOPE_LINK;
|
|
|
|
n->scope_set = true;
|
|
|
|
n->protocol = RTPROT_STATIC;
|
2019-05-14 09:43:14 +02:00
|
|
|
|
|
|
|
TAKE_PTR(n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_gateway(
|
|
|
|
const char *unit,
|
2013-10-17 03:18:36 +02:00
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
2013-11-19 16:17:55 +01:00
|
|
|
unsigned section_line,
|
2013-10-17 03:18:36 +02:00
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
2014-08-11 22:44:51 +02:00
|
|
|
|
2013-11-19 16:54:42 +01:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2018-12-03 10:22:05 +01:00
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
|
|
|
assert(filename);
|
2013-11-19 16:54:42 +01:00
|
|
|
assert(section);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2013-11-28 17:17:04 +01:00
|
|
|
if (streq(section, "Network")) {
|
2020-10-02 03:41:55 +02:00
|
|
|
/* we are not in an Route section, so use line number instead */
|
|
|
|
r = route_new_static(network, filename, line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-01-07 06:43:09 +01:00
|
|
|
} else {
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-01-07 06:43:09 +01:00
|
|
|
|
2020-02-05 05:41:30 +01:00
|
|
|
if (streq(rvalue, "_dhcp")) {
|
2020-01-07 06:43:09 +01:00
|
|
|
n->gateway_from_dhcp = true;
|
|
|
|
TAKE_PTR(n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-02-28 02:37:58 +01:00
|
|
|
if (n->family == AF_UNSPEC)
|
|
|
|
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
|
|
|
|
else
|
|
|
|
r = in_addr_from_string(n->family, rvalue, &n->gw);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-02-28 02:37:58 +01:00
|
|
|
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_preferred_src(
|
|
|
|
const char *unit,
|
2015-09-23 17:26:36 +02:00
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2018-12-03 10:22:05 +01:00
|
|
|
int r;
|
2015-09-23 17:26:36 +02:00
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-23 17:26:36 +02:00
|
|
|
|
2019-02-28 02:37:58 +01:00
|
|
|
if (n->family == AF_UNSPEC)
|
|
|
|
r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
|
|
|
|
else
|
|
|
|
r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
|
2015-09-23 17:26:36 +02:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
|
2019-02-28 02:37:58 +01:00
|
|
|
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
|
2015-09-23 17:26:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2015-09-23 17:26:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_destination(
|
|
|
|
const char *unit,
|
2013-11-19 16:54:42 +01:00
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
2014-08-11 22:44:51 +02:00
|
|
|
|
2013-11-19 16:54:42 +01:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2018-12-03 10:22:05 +01:00
|
|
|
union in_addr_union *buffer;
|
|
|
|
unsigned char *prefixlen;
|
2017-05-12 03:53:12 +02:00
|
|
|
int r;
|
2013-11-19 16:54:42 +01:00
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2013-11-19 16:54:42 +01:00
|
|
|
|
2014-12-04 15:52:21 +01:00
|
|
|
if (streq(lvalue, "Destination")) {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &n->dst;
|
|
|
|
prefixlen = &n->dst_prefixlen;
|
2014-12-04 15:52:21 +01:00
|
|
|
} else if (streq(lvalue, "Source")) {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &n->src;
|
|
|
|
prefixlen = &n->src_prefixlen;
|
2014-12-04 15:52:21 +01:00
|
|
|
} else
|
|
|
|
assert_not_reached(lvalue);
|
|
|
|
|
2019-02-28 02:37:58 +01:00
|
|
|
if (n->family == AF_UNSPEC)
|
|
|
|
r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
|
|
|
|
else
|
|
|
|
r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
|
2018-12-03 10:22:05 +01:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
|
2019-02-28 02:37:58 +01:00
|
|
|
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
|
2018-12-03 10:22:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2013-11-19 16:54:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2014-07-10 19:39:58 +02:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_route_priority(
|
|
|
|
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) {
|
|
|
|
|
2014-07-10 19:39:58 +02:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2014-07-10 19:39:58 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2014-07-10 19:39:58 +02:00
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
r = safe_atou32(rvalue, &n->priority);
|
2016-06-13 15:57:17 +02:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2016-06-13 15:57:17 +02:00
|
|
|
"Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2014-07-10 19:39:58 +02:00
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2014-07-10 19:39:58 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-09 16:22:34 +01:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_route_scope(
|
|
|
|
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) {
|
|
|
|
|
2015-02-09 16:22:34 +01:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2015-02-09 16:22:34 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2015-02-09 16:22:34 +01:00
|
|
|
|
2019-07-08 13:19:28 +02:00
|
|
|
r = route_scope_from_string(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route scope: %s", rvalue);
|
2015-02-09 16:22:34 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-08 13:19:28 +02:00
|
|
|
n->scope = r;
|
2019-07-07 02:40:17 +02:00
|
|
|
n->scope_set = true;
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2015-02-09 16:22:34 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2016-05-03 19:48:21 +02:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_route_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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2016-05-03 19:48:21 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2017-02-15 05:30:35 +01:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2016-05-03 19:48:21 +02:00
|
|
|
|
2019-07-08 13:19:28 +02:00
|
|
|
r = route_table_from_string(rvalue);
|
|
|
|
if (r >= 0)
|
|
|
|
n->table = r;
|
|
|
|
else {
|
|
|
|
r = safe_atou32(rvalue, &n->table);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-07-08 13:19:28 +02:00
|
|
|
"Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-05-03 19:48:21 +02:00
|
|
|
}
|
|
|
|
|
2019-07-07 02:40:17 +02:00
|
|
|
n->table_set = true;
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2016-05-03 19:48:21 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 11:22:30 +02:00
|
|
|
|
2020-07-16 07:48:08 +02:00
|
|
|
int config_parse_route_boolean(
|
2018-05-11 05:36:15 +02:00
|
|
|
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) {
|
|
|
|
|
2017-04-21 11:22:30 +02:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2017-04-21 11:22:30 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 11:22:30 +02:00
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-02-27 09:43:08 +01:00
|
|
|
"Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
|
2017-04-21 11:22:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-16 07:48:08 +02:00
|
|
|
if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink"))
|
|
|
|
n->gateway_onlink = r;
|
|
|
|
else if (streq(lvalue, "QuickAck"))
|
|
|
|
n->quickack = r;
|
|
|
|
else if (streq(lvalue, "FastOpenNoCookie"))
|
|
|
|
n->fast_open_no_cookie = r;
|
|
|
|
else if (streq(lvalue, "TTLPropagate"))
|
|
|
|
n->ttl_propagate = r;
|
|
|
|
else
|
|
|
|
assert_not_reached("Invalid lvalue");
|
2019-02-28 02:10:38 +01:00
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2017-04-25 09:32:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_ipv6_route_preference(
|
|
|
|
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) {
|
|
|
|
|
2017-04-25 09:32:59 +02:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2017-04-25 09:32:59 +02:00
|
|
|
int r;
|
|
|
|
|
2017-04-25 16:29:39 +02:00
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-25 16:29:39 +02:00
|
|
|
|
2017-04-25 09:32:59 +02:00
|
|
|
if (streq(rvalue, "low"))
|
|
|
|
n->pref = ICMPV6_ROUTER_PREF_LOW;
|
|
|
|
else if (streq(rvalue, "medium"))
|
|
|
|
n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
|
|
|
|
else if (streq(rvalue, "high"))
|
|
|
|
n->pref = ICMPV6_ROUTER_PREF_HIGH;
|
|
|
|
else {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
|
2017-04-25 09:32:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 11:22:30 +02:00
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2017-04-21 11:22:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-09 20:01:25 +02:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_route_protocol(
|
|
|
|
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) {
|
|
|
|
|
2017-05-09 20:01:25 +02:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2017-05-09 20:01:25 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-09 20:01:25 +02:00
|
|
|
|
2019-07-08 13:36:19 +02:00
|
|
|
r = route_protocol_from_string(rvalue);
|
|
|
|
if (r >= 0)
|
|
|
|
n->protocol = r;
|
2017-05-09 20:01:25 +02:00
|
|
|
else {
|
|
|
|
r = safe_atou8(rvalue , &n->protocol);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-02-28 02:39:14 +01:00
|
|
|
"Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
|
2017-05-09 20:01:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2017-05-09 20:01:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-19 16:28:26 +02:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_route_type(
|
|
|
|
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) {
|
|
|
|
|
2017-09-19 16:28:26 +02:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2019-07-07 01:43:33 +02:00
|
|
|
int t, r;
|
2017-09-19 16:28:26 +02:00
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-19 16:28:26 +02:00
|
|
|
|
2019-07-07 01:43:33 +02:00
|
|
|
t = route_type_from_string(rvalue);
|
|
|
|
if (t < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
2019-02-28 02:39:14 +01:00
|
|
|
"Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
|
2017-09-19 16:28:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-07 01:43:33 +02:00
|
|
|
n->type = (unsigned char) t;
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2017-09-19 16:28:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-12-29 15:18:05 +01:00
|
|
|
|
2018-05-11 05:36:15 +02:00
|
|
|
int config_parse_tcp_window(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2018-01-02 10:20:15 +01:00
|
|
|
Network *network = userdata;
|
2020-09-29 06:55:14 +02:00
|
|
|
uint32_t k;
|
2017-12-29 15:18:05 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-29 15:18:05 +01:00
|
|
|
|
2020-09-29 06:55:14 +02:00
|
|
|
r = safe_atou32(rvalue, &k);
|
2019-02-28 02:39:14 +01:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-02-28 02:39:14 +01:00
|
|
|
"Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-09-29 06:55:14 +02:00
|
|
|
if (k >= 1024) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
2019-02-28 02:39:14 +01:00
|
|
|
"Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
|
2017-12-29 15:18:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(lvalue, "InitialCongestionWindow"))
|
|
|
|
n->initcwnd = k;
|
|
|
|
else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
|
|
|
|
n->initrwnd = k;
|
2019-02-28 02:39:14 +01:00
|
|
|
else
|
|
|
|
assert_not_reached("Invalid TCP window type.");
|
2017-12-29 15:18:05 +01:00
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2017-12-29 15:18:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2018-01-20 00:49:15 +01:00
|
|
|
|
2018-05-21 13:33:36 +02:00
|
|
|
int config_parse_route_mtu(
|
|
|
|
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) {
|
|
|
|
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
2018-05-21 13:33:36 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2018-05-21 13:33:36 +02:00
|
|
|
|
|
|
|
r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-06-03 04:18:23 +02:00
|
|
|
TAKE_PTR(n);
|
2018-05-21 13:33:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2019-03-01 05:27:47 +01:00
|
|
|
|
2019-11-28 16:36:02 +01:00
|
|
|
int config_parse_multipath_route(
|
|
|
|
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_(route_free_or_set_invalidp) Route *n = NULL;
|
|
|
|
_cleanup_free_ char *word = NULL, *buf = NULL;
|
|
|
|
_cleanup_free_ MultipathRoute *m = NULL;
|
|
|
|
Network *network = userdata;
|
|
|
|
const char *p, *ip, *dev;
|
|
|
|
union in_addr_union a;
|
|
|
|
int family, r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_new_static(network, filename, section_line, &n);
|
2020-07-16 07:48:08 +02:00
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to allocate route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-28 16:36:02 +01:00
|
|
|
|
|
|
|
if (isempty(rvalue)) {
|
|
|
|
n->multipath_routes = ordered_set_free_free(n->multipath_routes);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = new0(MultipathRoute, 1);
|
|
|
|
if (!m)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
p = rvalue;
|
|
|
|
r = extract_first_word(&p, &word, NULL, 0);
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r <= 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Invalid multipath route option, ignoring assignment: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = strchr(word, '@');
|
|
|
|
if (dev) {
|
|
|
|
buf = strndup(word, dev - word);
|
|
|
|
if (!buf)
|
|
|
|
return log_oom();
|
|
|
|
ip = buf;
|
|
|
|
dev++;
|
|
|
|
} else
|
|
|
|
ip = word;
|
|
|
|
|
|
|
|
r = in_addr_from_string_auto(ip, &family, &a);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
m->gateway.address = a;
|
|
|
|
m->gateway.family = family;
|
|
|
|
|
|
|
|
if (dev) {
|
2020-01-11 11:21:01 +01:00
|
|
|
r = resolve_interface(NULL, dev);
|
2019-11-28 16:36:02 +01:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Invalid interface name or index, ignoring assignment: %s", dev);
|
|
|
|
return 0;
|
|
|
|
}
|
2019-12-18 13:54:13 +01:00
|
|
|
m->ifindex = r;
|
2019-11-28 16:36:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isempty(p)) {
|
|
|
|
r = safe_atou32(p, &m->weight);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Invalid multipath route weight, ignoring assignment: %s", p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (m->weight == 0 || m->weight > 256) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Invalid multipath route weight, ignoring assignment: %s", p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = ordered_set_ensure_allocated(&n->multipath_routes, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = ordered_set_put(n->multipath_routes, m);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-28 16:36:02 +01:00
|
|
|
"Failed to store multipath route, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAKE_PTR(m);
|
|
|
|
TAKE_PTR(n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 03:08:39 +02:00
|
|
|
static int route_section_verify(Route *route, Network *network) {
|
2019-03-01 05:27:47 +01:00
|
|
|
if (section_is_invalid(route->section))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (route->family == AF_UNSPEC) {
|
|
|
|
assert(route->section);
|
|
|
|
|
|
|
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"%s: Route section without Gateway=, Destination=, Source=, "
|
|
|
|
"or PreferredSource= field configured. "
|
|
|
|
"Ignoring [Route] section from line %u.",
|
|
|
|
route->section->filename, route->section->line);
|
|
|
|
}
|
|
|
|
|
2020-02-26 07:42:32 +01:00
|
|
|
if (!route->table_set && network->vrf) {
|
|
|
|
route->table = VRF(network->vrf)->table;
|
|
|
|
route->table_set = true;
|
|
|
|
}
|
|
|
|
|
2019-11-26 04:41:54 +01:00
|
|
|
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 && route->family != AF_INET6) {
|
|
|
|
if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
|
|
|
|
route->scope = RT_SCOPE_HOST;
|
|
|
|
else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
|
|
|
|
route->scope = RT_SCOPE_LINK;
|
2019-07-07 02:40:17 +02:00
|
|
|
}
|
|
|
|
|
2020-08-13 17:04:00 +02:00
|
|
|
if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
|
|
|
|
log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
|
|
|
|
route->scope = RT_SCOPE_UNIVERSE;
|
|
|
|
}
|
|
|
|
|
2020-08-13 11:55:06 +02:00
|
|
|
if (route->family == AF_INET6 && route->priority == 0)
|
|
|
|
route->priority = IP6_RT_PRIO_USER;
|
|
|
|
|
2020-10-02 05:34:19 +02:00
|
|
|
if (ordered_hashmap_isempty(network->addresses_by_section) &&
|
2019-03-01 05:27:47 +01:00
|
|
|
in_addr_is_null(route->family, &route->gw) == 0 &&
|
|
|
|
route->gateway_onlink < 0) {
|
|
|
|
log_warning("%s: Gateway= without static address configured. "
|
|
|
|
"Enabling GatewayOnLink= option.",
|
|
|
|
network->filename);
|
|
|
|
route->gateway_onlink = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-02 03:08:39 +02:00
|
|
|
|
2020-10-06 20:21:59 +02:00
|
|
|
void network_drop_invalid_routes(Network *network) {
|
2020-10-02 03:41:55 +02:00
|
|
|
Route *route;
|
2020-10-02 03:08:39 +02:00
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
2020-10-02 03:41:55 +02:00
|
|
|
HASHMAP_FOREACH(route, network->routes_by_section)
|
2020-10-02 03:08:39 +02:00
|
|
|
if (route_section_verify(route, network) < 0)
|
|
|
|
route_free(route);
|
|
|
|
}
|