Systemd/src/network/networkd-manager.c

1887 lines
62 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/fib_rules.h>
#include "sd-daemon.h"
#include "sd-netlink.h"
#include "alloc-util.h"
#include "bus-util.h"
#include "conf-parser.h"
#include "def.h"
2019-03-09 02:37:12 +01:00
#include "device-private.h"
#include "device-util.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "local-addresses.h"
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-manager.h"
2019-05-24 22:08:13 +02:00
#include "networkd-speed-meter.h"
#include "ordered-set.h"
#include "path-util.h"
#include "set.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tmpfile-util.h"
#include "udev-util.h"
#include "virt.h"
/* use 8 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (8*1024*1024)
static int setup_default_address_pool(Manager *m) {
AddressPool *p;
int r;
assert(m);
/* Add in the well-known private address ranges. */
r = address_pool_new_from_string(m, &p, AF_INET6, "fd00::", 8);
if (r < 0)
return r;
r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
if (r < 0)
return r;
r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
if (r < 0)
return r;
r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
if (r < 0)
return r;
return 0;
}
2015-02-03 15:44:12 +01:00
static int manager_reset_all(Manager *m) {
Link *link;
Iterator i;
int r;
assert(m);
HASHMAP_FOREACH(link, m->links, i) {
r = link_carrier_reset(link);
if (r < 0)
log_link_warning_errno(link, r, "Could not reset carrier: %m");
2015-02-03 15:44:12 +01:00
}
return 0;
}
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
2015-02-03 15:44:12 +01:00
Manager *m = userdata;
int b, r;
assert(message);
assert(m);
2015-02-03 15:44:12 +01:00
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
return 0;
}
if (b)
return 0;
log_debug("Coming back from suspend, resetting all connections...");
(void) manager_reset_all(m);
2015-02-03 15:44:12 +01:00
return 0;
}
static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
2015-02-03 15:44:12 +01:00
assert(message);
2015-02-03 15:44:12 +01:00
assert(m);
/* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */
if (m->dynamic_hostname)
(void) manager_set_hostname(m, m->dynamic_hostname);
if (m->dynamic_timezone)
(void) manager_set_timezone(m, m->dynamic_timezone);
if (m->links_requesting_uuid)
(void) manager_request_product_uuid(m, NULL);
2015-02-03 15:44:12 +01:00
return 0;
}
2015-02-03 15:44:12 +01:00
int manager_connect_bus(Manager *m) {
int r;
assert(m);
2015-02-03 15:44:12 +01:00
if (m->bus)
2015-02-03 15:44:12 +01:00
return 0;
2015-08-06 00:31:09 +02:00
2018-04-17 16:55:27 +02:00
r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
2015-02-03 15:44:12 +01:00
if (r < 0)
return log_error_errno(r, "Failed to connect to bus: %m");
2015-02-03 15:44:12 +01:00
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
if (r < 0)
return log_error_errno(r, "Failed to add manager object vtable: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
if (r < 0)
return log_error_errno(r, "Failed to add link object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
if (r < 0)
return log_error_errno(r, "Failed to add link enumerator: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
if (r < 0)
return log_error_errno(r, "Failed to add network object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
if (r < 0)
return log_error_errno(r, "Failed to add network enumerator: %m");
Revert "network: set DynamicUser= to systemd-networkd.service" This reverts commit d4e9e574ea0b5d23598a317e68399584d229568b. (systemd.conf.m4 part was already reverted in 5b5d82615011b9827466b7cd5756da35627a1608.) Together those reverts should "fix" #10025 and #10011. ("fix" is in quotes because this doesn't really fix the underlying issue, which is combining DynamicUser= with strict container sandbox, but it avoids the problem by not using that feature in our default installation.) Dynamic users don't work well if the service requires matching configuration in other places, for example dbus policy. This is true for those three services. In effect, distros create the user statically [1, 2]. Dynamic users make more sense for "add-on" services where not creating the user, or more precisely, creating the user lazily, can save resources. For "basic" services, if we are going to create the user on package installation anyway, setting DynamicUser= just creates unneeded confusion. The only case where it is actually used is when somebody forgets to do system configuration. But it's better to have the service fail cleanly in this case too. If we want to turn on some side-effect of DynamicUser=yes for those services, we should just do that directly through fine-grained options. By not using DynamicUser= we also avoid the need to restart dbus. [1] https://salsa.debian.org/systemd-team/systemd/commit/bd9bf307274faca24699c0c2d67cb86f18c0b2cb [2] https://src.fedoraproject.org/rpms/systemd/blob/48ac1cebdedb055d9daf3dfe28c7bde80103f7a1/f/systemd.spec#_473 (Fedora does not create systemd-timesync user.)
2018-09-19 10:06:09 +02:00
r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = sd_bus_match_signal_async(
m->bus,
2018-07-17 05:36:02 +02:00
NULL,
"org.freedesktop.DBus.Local",
NULL,
"org.freedesktop.DBus.Local",
"Connected",
on_connected, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match on Connected signal: %m");
r = sd_bus_match_signal_async(
m->bus,
2018-07-17 05:36:02 +02:00
NULL,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"PrepareForSleep",
match_prepare_for_sleep, NULL, m);
if (r < 0)
log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
2015-02-03 15:44:12 +01:00
return 0;
}
static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
Manager *m = userdata;
2019-03-09 02:37:12 +01:00
DeviceAction action;
Link *link = NULL;
int r, ifindex;
assert(m);
assert(device);
2019-03-09 02:37:12 +01:00
r = device_get_action(device, &action);
if (r < 0) {
2019-03-09 02:37:12 +01:00
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
return 0;
}
2019-03-09 02:37:12 +01:00
if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_CHANGE, DEVICE_ACTION_MOVE)) {
log_device_debug(device, "Ignoring udev %s event for device.", device_action_to_string(action));
return 0;
}
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0) {
log_device_debug_errno(device, r, "Ignoring udev ADD event for device without ifindex or with invalid ifindex: %m");
return 0;
}
r = device_is_renaming(device);
if (r < 0) {
2019-03-09 02:37:12 +01:00
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
device_action_to_string(action));
return 0;
}
if (r > 0) {
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m");
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0) {
if (r != -ENODEV)
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
return 0;
}
(void) link_initialized(link, device);
return 0;
}
static int manager_connect_udev(Manager *m) {
int r;
/* udev does not initialize devices inside containers,
* so we rely on them being already initialized before
* entering the container */
if (detect_container() > 0)
return 0;
r = sd_device_monitor_new(&m->device_monitor);
if (r < 0)
return log_error_errno(r, "Failed to initialize device monitor: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter: %m");
r = sd_device_monitor_attach_event(m->device_monitor, m->event);
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
return 0;
}
2015-10-25 14:46:21 +01:00
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
uint16_t type;
uint32_t ifindex, priority = 0;
unsigned char protocol, scope, tos, table, rt_type;
2015-10-25 14:46:21 +01:00
int family;
unsigned char dst_prefixlen, src_prefixlen;
union in_addr_union dst = IN_ADDR_NULL, gw = IN_ADDR_NULL, src = IN_ADDR_NULL, prefsrc = IN_ADDR_NULL;
2015-10-25 14:46:21 +01:00
Route *route = NULL;
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_warning_errno(r, "rtnl: failed to receive route, ignoring: %m");
2015-10-25 14:46:21 +01:00
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");
2015-10-25 14:46:21 +01:00
return 0;
2017-09-28 08:37:38 +02:00
} else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
log_warning("rtnl: received unexpected message type when processing route, ignoring");
2015-10-25 14:46:21 +01:00
return 0;
}
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
if (r == -ENODATA) {
log_debug("rtnl: received route without ifindex, ignoring");
return 0;
} else if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
return 0;
} else {
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 for nonexistent link (%d), ignoring", ifindex);
return 0;
}
}
r = sd_rtnl_message_route_get_family(message, &family);
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
log_link_warning(link, "rtnl: received address with invalid family, ignoring");
2015-10-25 14:46:21 +01:00
return 0;
}
r = sd_rtnl_message_route_get_protocol(message, &protocol);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get route protocol: %m");
return 0;
}
switch (family) {
case AF_INET:
r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
return 0;
}
break;
case AF_INET6:
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
return 0;
}
break;
default:
2017-09-28 08:38:50 +02:00
assert_not_reached("Received unsupported address family");
2015-10-25 14:46:21 +01:00
return 0;
}
r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_scope(message, &scope);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_tos(message, &tos);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_type(message, &rt_type);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid type, ignoring: %m");
return 0;
}
2015-10-25 14:46:21 +01:00
r = sd_rtnl_message_route_get_table(message, &table);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
return 0;
}
(void) route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
2015-10-25 14:46:21 +01:00
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
*buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
if (!in_addr_is_null(family, &dst)) {
(void) in_addr_to_string(family, &dst, &buf_dst);
(void) asprintf(&buf_dst_prefixlen, "/%u", dst_prefixlen);
}
if (!in_addr_is_null(family, &src))
(void) in_addr_to_string(family, &src, &buf_src);
if (!in_addr_is_null(family, &gw))
(void) in_addr_to_string(family, &gw, &buf_gw);
if (!in_addr_is_null(family, &prefsrc))
(void) in_addr_to_string(family, &prefsrc, &buf_prefsrc);
log_link_debug(link,
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s",
type == RTM_DELROUTE ? "Removing" : route ? "Updating" : "Adding",
strna(buf_dst), strempty(buf_dst_prefixlen),
strna(buf_src), strna(buf_gw), strna(buf_prefsrc));
}
2015-10-25 14:46:21 +01:00
switch (type) {
case RTM_NEWROUTE:
if (!route) {
/* A route appeared that we did not request */
r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to add route, ignoring: %m");
2015-10-25 14:46:21 +01:00
return 0;
}
2015-10-25 14:46:21 +01:00
}
route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol, rt_type);
2015-10-25 14:46:21 +01:00
break;
case RTM_DELROUTE:
route_free(route);
2015-10-25 14:46:21 +01:00
break;
2015-10-25 14:46:21 +01:00
default:
assert_not_reached("Received invalid RTNL message type");
}
return 1;
}
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
_cleanup_free_ char *buf = NULL;
Manager *m = userdata;
Link *link = NULL;
uint16_t type;
unsigned char flags, prefixlen, scope;
union in_addr_union in_addr = IN_ADDR_NULL;
struct ifa_cacheinfo cinfo;
Address *address = NULL;
char valid_buf[FORMAT_TIMESPAN_MAX];
const char *valid_str = NULL;
int ifindex, family, 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_warning_errno(r, "rtnl: failed to receive address, ignoring: %m");
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;
2017-09-28 08:37:38 +02:00
} else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
log_warning("rtnl: received unexpected message type when processing address, ignoring");
return 0;
}
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from address, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received address message with invalid ifindex, ignoring: %d", ifindex);
return 0;
} else {
r = link_get(m, ifindex, &link);
if (r < 0 || !link) {
/* when enumerating we might be out of sync, but we will
* get the address again, so just ignore it */
if (!m->enumerating)
log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
return 0;
}
}
r = sd_rtnl_message_addr_get_family(message, &family);
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
log_link_warning(link, "rtnl: received address with invalid family, ignoring");
return 0;
}
r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_addr_get_scope(message, &scope);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
return 0;
}
r = sd_rtnl_message_addr_get_flags(message, &flags);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
return 0;
}
switch (family) {
case AF_INET:
r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
return 0;
}
break;
case AF_INET6:
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
return 0;
}
break;
default:
assert_not_reached("Received unsupported address family");
}
r = in_addr_to_string(family, &in_addr, &buf);
if (r < 0) {
log_link_warning_errno(link, r, "Could not print address, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
return 0;
} else if (r >= 0 && cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
cinfo.ifa_valid * USEC_PER_SEC,
USEC_PER_SEC);
(void) address_get(link, family, &in_addr, prefixlen, &address);
switch (type) {
case RTM_NEWADDR:
if (address)
2015-11-10 21:45:41 +01:00
log_link_debug(link, "Updating address: %s/%u (valid %s%s)", buf, prefixlen,
valid_str ? "for " : "forever", strempty(valid_str));
else {
/* An address appeared that we did not request */
r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to add address %s/%u, ignoring: %m", buf, prefixlen);
return 0;
} else
2015-11-10 21:45:41 +01:00
log_link_debug(link, "Adding address: %s/%u (valid %s%s)", buf, prefixlen,
valid_str ? "for " : "forever", strempty(valid_str));
}
r = address_update(address, flags, scope, &cinfo);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to update address %s/%u, ignoring: %m", buf, prefixlen);
return 0;
}
break;
case RTM_DELADDR:
if (address) {
2015-11-10 21:45:41 +01:00
log_link_debug(link, "Removing address: %s/%u (valid %s%s)", buf, prefixlen,
valid_str ? "for " : "forever", strempty(valid_str));
(void) address_drop(address);
} else
log_link_warning(link, "Removing non-existent address: %s/%u (valid %s%s), ignoring", buf, prefixlen,
valid_str ? "for " : "forever", strempty(valid_str));
break;
default:
assert_not_reached("Received invalid RTNL message type");
}
return 1;
}
2015-06-12 16:31:33 +02:00
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
NetDev *netdev = NULL;
uint16_t type;
const char *name;
int r, ifindex;
assert(rtnl);
assert(message);
assert(m);
2015-06-12 16:31:33 +02:00
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_warning_errno(r, "rtnl: Could not receive link, ignoring: %m");
return 0;
}
2015-06-12 16:31:33 +02:00
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;
2017-09-28 08:37:38 +02:00
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
log_warning("rtnl: Received unexpected message type when processing link, ignoring");
return 0;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
if (r < 0) {
log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex);
return 0;
}
2015-06-12 16:31:33 +02:00
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
if (r < 0) {
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
return 0;
}
(void) link_get(m, ifindex, &link);
(void) netdev_get(m, name, &netdev);
switch (type) {
case RTM_NEWLINK:
if (!link) {
/* link is new, so add it */
r = link_add(m, message, &link);
if (r < 0) {
log_warning_errno(r, "Could not add new link, ignoring: %m");
return 0;
}
}
if (netdev) {
/* netdev exists, so make sure the ifindex matches */
r = netdev_set_ifindex(netdev, message);
if (r < 0) {
log_warning_errno(r, "Could not set ifindex on netdev, ignoring: %m");
return 0;
}
}
r = link_update(link, message);
if (r < 0) {
log_warning_errno(r, "Could not update link, ignoring: %m");
return 0;
}
break;
case RTM_DELLINK:
link_drop(link);
netdev_drop(netdev);
break;
default:
assert_not_reached("Received invalid RTNL message type.");
}
return 1;
}
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0, protocol = 0;
struct fib_rule_port_range sport = {}, dport = {};
union in_addr_union to = IN_ADDR_NULL, from = IN_ADDR_NULL;
RoutingPolicyRule *rule = NULL;
uint32_t fwmark = 0, table = 0;
const char *iif = NULL, *oif = NULL;
Manager *m = userdata;
uint16_t type;
int family;
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_warning_errno(r, "rtnl: failed to receive rule, ignoring: %m");
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_NEWRULE, RTM_DELRULE)) {
log_warning("rtnl: received unexpected message type '%u' when processing rule, ignoring", type);
return 0;
}
r = sd_rtnl_message_get_family(message, &family);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
return 0;
} else if (!IN_SET(family, AF_INET, AF_INET6)) {
log_debug("rtnl: received address with invalid family %u, ignoring", family);
return 0;
}
switch (family) {
case AF_INET:
r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
return 0;
} else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
if (r < 0) {
2018-06-18 22:43:12 +02:00
log_warning_errno(r, "rtnl: failed to retrieve rule from prefix length, ignoring: %m");
return 0;
}
}
r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
return 0;
} else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
if (r < 0) {
2018-06-18 22:43:12 +02:00
log_warning_errno(r, "rtnl: failed to retrieve rule to prefix length, ignoring: %m");
return 0;
}
}
break;
case AF_INET6:
r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
return 0;
} else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
if (r < 0) {
2018-06-18 22:43:12 +02:00
log_warning_errno(r, "rtnl: failed to retrieve rule from prefix length, ignoring: %m");
return 0;
}
}
r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
return 0;
} else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
if (r < 0) {
2018-06-18 22:43:12 +02:00
log_warning_errno(r, "rtnl: failed to retrieve rule to prefix length, ignoring: %m");
return 0;
}
}
break;
default:
2017-09-28 08:38:50 +02:00
assert_not_reached("Received unsupported address family");
}
if (from_prefixlen == 0 && to_prefixlen == 0)
return 0;
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u32(message, FRA_TABLE, &table);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
return 0;
}
r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &protocol);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(sport), (void *) &sport);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(dport), (void *) &dport);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
return 0;
}
(void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule);
switch (type) {
case RTM_NEWRULE:
if (!rule) {
r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule);
if (r < 0) {
log_warning_errno(r, "Could not add rule, ignoring: %m");
return 0;
}
}
break;
case RTM_DELRULE:
routing_policy_rule_free(rule);
break;
default:
assert_not_reached("Received invalid RTNL message type");
}
return 1;
}
static int systemd_netlink_fd(void) {
int n, fd, rtnl_fd = -EINVAL;
n = sd_listen_fds(true);
if (n <= 0)
return -EINVAL;
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (rtnl_fd >= 0)
return -EINVAL;
rtnl_fd = fd;
}
}
return rtnl_fd;
}
static int manager_connect_genl(Manager *m) {
int r;
assert(m);
r = sd_genl_socket_open(&m->genl);
if (r < 0)
return r;
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
if (r < 0)
return r;
r = sd_netlink_attach_event(m->genl, m->event, 0);
if (r < 0)
return r;
return 0;
}
static int manager_connect_rtnl(Manager *m) {
int fd, r;
assert(m);
fd = systemd_netlink_fd();
if (fd < 0)
2015-06-12 16:31:33 +02:00
r = sd_netlink_open(&m->rtnl);
else
2015-06-12 16:31:33 +02:00
r = sd_netlink_open_fd(&m->rtnl, fd);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
2015-10-25 14:46:21 +01:00
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
2015-10-25 14:46:21 +01:00
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
if (r < 0)
return r;
return 0;
}
static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
char *p;
int r;
assert(s);
assert(address);
r = in_addr_to_string(address->family, &address->address, &p);
if (r < 0)
return r;
r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
int r, c = 0;
unsigned i;
assert(s);
assert(addresses || n == 0);
for (i = 0; i < n; i++) {
r = ordered_set_put_in_addr_data(s, addresses+i);
if (r < 0)
return r;
c += r;
}
return c;
}
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
int r;
assert(s);
assert(address);
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
if (r < 0)
return r;
r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_in4_addrv(OrderedSet *s,
const struct in_addr *addresses,
size_t n,
bool (*predicate)(const struct in_addr *addr)) {
int r, c = 0;
size_t i;
assert(s);
assert(n == 0 || addresses);
for (i = 0; i < n; i++) {
if (predicate && !predicate(&addresses[i]))
continue;
r = ordered_set_put_in4_addr(s, addresses+i);
if (r < 0)
return r;
c += r;
}
return c;
}
static int manager_save(Manager *m) {
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
Link *link;
Iterator i;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
const char *operstate_str;
int r;
assert(m);
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
route_domains = ordered_set_new(&dns_name_hash_ops);
if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links, i) {
if (link->flags & IFF_LOOPBACK)
continue;
if (link->operstate > operstate)
operstate = link->operstate;
if (!link->network)
continue;
/* First add the static configured entries */
r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
r = ordered_set_put_strdupv(ntp, link->network->ntp);
if (r < 0)
return r;
r = ordered_set_put_string_set(search_domains, link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_string_set(route_domains, link->network->route_domains);
if (r < 0)
return r;
if (!link->dhcp_lease)
continue;
/* Secondly, add the entries acquired via DHCP */
if (link->network->dhcp_use_dns) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_ntp) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
char **domains = NULL;
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(target_domains, domainname);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(target_domains, domains);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
}
}
operstate_str = link_operstate_to_string(operstate);
assert(operstate_str);
r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0)
return r;
(void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
"OPER_STATE=%s\n", operstate_str);
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
ordered_set_print(f, "DOMAINS=", search_domains);
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
r = routing_policy_serialize_rules(m->rules, f);
if (r < 0)
goto fail;
r = fflush_and_check(f);
if (r < 0)
goto fail;
if (rename(temp_path, m->state_file) < 0) {
r = -errno;
goto fail;
}
if (m->operational_state != operstate) {
m->operational_state = operstate;
r = manager_send_changed(m, "OperationalState", NULL);
if (r < 0)
log_error_errno(r, "Could not emit changed OperationalState: %m");
}
m->dirty = false;
return 0;
fail:
(void) unlink(m->state_file);
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
}
static int manager_dirty_handler(sd_event_source *s, void *userdata) {
Manager *m = userdata;
Link *link;
Iterator i;
assert(m);
if (m->dirty)
manager_save(m);
2018-11-12 07:21:40 +01:00
SET_FOREACH(link, m->dirty_links, i)
if (link_save(link) >= 0)
link_clean(link);
return 1;
}
Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
assert_return(m, NULL);
assert_return(addr, NULL);
return hashmap_get(m->dhcp6_prefixes, addr);
}
static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
log_link_debug_errno(link, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
return 0;
}
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
_cleanup_free_ struct in6_addr *a = NULL;
_cleanup_free_ char *buf = NULL;
Link *assigned_link;
Route *route;
int r;
assert_return(m, -EINVAL);
assert_return(addr, -EINVAL);
r = route_add(link, AF_INET6, (union in_addr_union *) addr, 64,
0, 0, 0, &route);
if (r < 0)
return r;
r = route_configure(route, link, dhcp6_route_add_handler);
if (r < 0)
return r;
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
assigned_link = hashmap_get(m->dhcp6_prefixes, addr);
if (assigned_link) {
assert(assigned_link == link);
return 0;
}
a = newdup(struct in6_addr, addr, 1);
if (!a)
return -ENOMEM;
2019-05-18 05:29:40 +02:00
r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &in6_addr_hash_ops);
if (r < 0)
return r;
r = hashmap_put(m->dhcp6_prefixes, a, link);
if (r < 0)
return r;
TAKE_PTR(a);
link_ref(link);
return 0;
}
static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
r = sd_netlink_message_get_errno(m);
if (r < 0)
log_link_debug_errno(link, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
return 1;
}
static int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
_cleanup_free_ struct in6_addr *a = NULL;
_cleanup_(link_unrefp) Link *l = NULL;
_cleanup_free_ char *buf = NULL;
Route *route;
int r;
assert_return(m, -EINVAL);
assert_return(addr, -EINVAL);
l = hashmap_remove2(m->dhcp6_prefixes, addr, (void **) &a);
if (!l)
return -EINVAL;
(void) sd_radv_remove_prefix(l->radv, addr, 64);
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, 0, 0, 0, &route);
if (r < 0)
return r;
r = route_remove(route, l, dhcp6_route_remove_handler);
if (r < 0)
return r;
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
return 0;
}
int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) {
struct in6_addr *addr;
Iterator i;
Link *l;
assert_return(m, -EINVAL);
2018-01-16 17:29:13 +01:00
assert_return(link, -EINVAL);
HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i)
if (l == link)
(void) manager_dhcp6_prefix_remove(m, addr);
return 0;
}
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
2019-05-24 22:08:13 +02:00
m = new(Manager, 1);
if (!m)
return -ENOMEM;
2019-05-24 22:08:13 +02:00
*m = (Manager) {
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
};
m->state_file = strdup("/run/systemd/netif/state");
if (!m->state_file)
return -ENOMEM;
r = sd_event_default(&m->event);
if (r < 0)
return r;
(void) sd_event_set_watchdog(m->event, true);
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
if (r < 0)
return r;
r = manager_connect_rtnl(m);
if (r < 0)
return r;
r = manager_connect_genl(m);
if (r < 0)
return r;
r = manager_connect_udev(m);
if (r < 0)
return r;
r = sd_resolve_default(&m->resolve);
if (r < 0)
return r;
r = sd_resolve_attach_event(m->resolve, m->event, 0);
if (r < 0)
return r;
r = setup_default_address_pool(m);
if (r < 0)
return r;
m->duid.type = DUID_TYPE_EN;
2016-03-31 01:33:55 +02:00
(void) routing_policy_load_rules(m->state_file, &m->rules_saved);
*ret = TAKE_PTR(m);
return 0;
}
void manager_free(Manager *m) {
struct in6_addr *a;
AddressPool *pool;
Link *link;
if (!m)
return;
free(m->state_file);
while ((a = hashmap_first_key(m->dhcp6_prefixes)))
(void) manager_dhcp6_prefix_remove(m, a);
hashmap_free(m->dhcp6_prefixes);
while ((link = hashmap_steal_first(m->links))) {
if (link->dhcp6_client)
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
(void) link_stop_clients(link, true);
link_unref(link);
}
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
m->links = hashmap_free_with_destructor(m->links, link_unref);
m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
2015-02-08 13:29:35 +01:00
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
while ((pool = m->address_pools))
address_pool_free(pool);
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */
m->rules = set_free_with_destructor(m->rules, routing_policy_rule_free);
m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free);
set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
sd_resolve_unref(m->resolve);
2019-05-24 22:08:13 +02:00
sd_event_source_unref(m->speed_meter_event_source);
sd_event_unref(m->event);
sd_device_monitor_unref(m->device_monitor);
sd_bus_flush_close_unref(m->bus);
free(m->dynamic_timezone);
free(m->dynamic_hostname);
free(m);
}
int manager_start(Manager *m) {
Link *link;
Iterator i;
2019-05-24 22:08:13 +02:00
int r;
assert(m);
2019-05-24 22:08:13 +02:00
r = manager_start_speed_meter(m);
if (r < 0)
return log_error_errno(r, "Failed to initialize speed meter: %m");
/* The dirty handler will deal with future serialization, but the first one
must be done explicitly. */
manager_save(m);
HASHMAP_FOREACH(link, m->links, i)
link_save(link);
return 0;
}
int manager_load_config(Manager *m) {
int r;
/* update timestamp */
paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true);
r = netdev_load(m);
if (r < 0)
return r;
r = network_load(m);
if (r < 0)
return r;
return 0;
}
2013-11-14 16:22:51 +01:00
bool manager_should_reload(Manager *m) {
return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false);
}
int manager_rtnl_enumerate_links(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
2015-06-12 16:31:33 +02:00
sd_netlink_message *link;
2013-11-14 16:22:51 +01:00
int r;
assert(m);
assert(m->rtnl);
r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
2013-11-14 16:22:51 +01:00
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_call(m->rtnl, req, 0, &reply);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
for (link = reply; link; link = sd_netlink_message_next(link)) {
int k;
m->enumerating = true;
k = manager_rtnl_process_link(m->rtnl, link, m);
if (k < 0)
r = k;
m->enumerating = false;
}
return r;
2013-11-14 16:22:51 +01:00
}
int manager_rtnl_enumerate_addresses(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
2015-06-12 16:31:33 +02:00
sd_netlink_message *addr;
int r;
assert(m);
assert(m->rtnl);
r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
r = sd_netlink_call(m->rtnl, req, 0, &reply);
if (r < 0)
return r;
2015-06-12 16:31:33 +02:00
for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
int k;
m->enumerating = true;
k = manager_rtnl_process_address(m->rtnl, addr, m);
if (k < 0)
r = k;
m->enumerating = false;
}
return r;
}
2015-10-25 14:46:21 +01:00
int manager_rtnl_enumerate_routes(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
2015-10-25 14:46:21 +01:00
sd_netlink_message *route;
int r;
assert(m);
assert(m->rtnl);
r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
if (r < 0)
return r;
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
r = sd_netlink_call(m->rtnl, req, 0, &reply);
if (r < 0)
return r;
for (route = reply; route; route = sd_netlink_message_next(route)) {
int k;
m->enumerating = true;
k = manager_rtnl_process_route(m->rtnl, route, m);
if (k < 0)
r = k;
m->enumerating = false;
}
return r;
}
int manager_rtnl_enumerate_rules(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
sd_netlink_message *rule;
int r;
assert(m);
assert(m->rtnl);
r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0);
if (r < 0)
return r;
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
r = sd_netlink_call(m->rtnl, req, 0, &reply);
networkd: Don't stop networkd if CONFIG_FIB_RULES=n in kernel (#7030) If FIB Rules are not supported by the kernel then networkd fails to start as it retuns error=-EOPNOTSUPP. In this case just ignore and let start networkd. ``` sendto(5, {{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}, 28, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 16) = 28 recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 48 recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base={{len=48, type=NLMSG_ERROR, flags=0, seq=8, pid=8856}, {error=-EOPNOTSUPP, msg={{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}}}, iov_len=7416}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=0}, MSG_TRUNC) = 48 ``` ``` Oct 08 10:22:24 naomi systemd[1]: Starting Network Service... Oct 08 10:22:24 naomi systemd-networkd[983]: Could not enumerate rules: Operation not supported Oct 08 10:22:24 naomi systemd[1]: systemd-networkd.service: Main process exited, code=exited, status=1/FAILURE ``` Fixes #7027
2017-10-18 08:25:57 +02:00
if (r < 0) {
if (r == -EOPNOTSUPP) {
log_debug("FIB Rules are not supported by the kernel. Ignoring.");
return 0;
}
return r;
networkd: Don't stop networkd if CONFIG_FIB_RULES=n in kernel (#7030) If FIB Rules are not supported by the kernel then networkd fails to start as it retuns error=-EOPNOTSUPP. In this case just ignore and let start networkd. ``` sendto(5, {{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}, 28, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 16) = 28 recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 48 recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base={{len=48, type=NLMSG_ERROR, flags=0, seq=8, pid=8856}, {error=-EOPNOTSUPP, msg={{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}}}, iov_len=7416}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=0}, MSG_TRUNC) = 48 ``` ``` Oct 08 10:22:24 naomi systemd[1]: Starting Network Service... Oct 08 10:22:24 naomi systemd-networkd[983]: Could not enumerate rules: Operation not supported Oct 08 10:22:24 naomi systemd[1]: systemd-networkd.service: Main process exited, code=exited, status=1/FAILURE ``` Fixes #7027
2017-10-18 08:25:57 +02:00
}
for (rule = reply; rule; rule = sd_netlink_message_next(rule)) {
int k;
m->enumerating = true;
k = manager_rtnl_process_rule(m->rtnl, rule, m);
if (k < 0)
r = k;
m->enumerating = false;
}
return r;
}
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
AddressPool *p;
int r;
assert(m);
assert(prefixlen > 0);
assert(found);
LIST_FOREACH(address_pools, p, m->address_pools) {
if (p->family != family)
continue;
r = address_pool_acquire(p, prefixlen, found);
if (r != 0)
return r;
}
return 0;
}
Link* manager_find_uplink(Manager *m, Link *exclude) {
_cleanup_free_ struct local_address *gateways = NULL;
int n, i;
assert(m);
/* Looks for a suitable "uplink", via black magic: an
* interface that is up and where the default route with the
* highest priority points to. */
n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways);
if (n < 0) {
log_warning_errno(n, "Failed to determine list of default gateways: %m");
return NULL;
}
for (i = 0; i < n; i++) {
Link *link;
link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex));
if (!link) {
2015-08-27 20:23:17 +02:00
log_debug("Weird, found a gateway for a link we don't know. Ignoring.");
continue;
}
if (link == exclude)
continue;
if (link->operstate < LINK_OPERSTATE_ROUTABLE)
continue;
return link;
}
return NULL;
}
void manager_dirty(Manager *manager) {
assert(manager);
/* the serialized state in /run is no longer up-to-date */
manager->dirty = true;
}
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
Manager *manager = userdata;
const sd_bus_error *e;
assert(m);
assert(manager);
e = sd_bus_message_get_error(m);
if (e)
log_warning_errno(sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message);
return 1;
}
int manager_set_hostname(Manager *m, const char *hostname) {
int r;
log_debug("Setting transient hostname: '%s'", strna(hostname));
if (free_and_strdup(&m->dynamic_hostname, hostname) < 0)
return log_oom();
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, setting hostname later.");
return 0;
}
r = sd_bus_call_method_async(
m->bus,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
"SetHostname",
set_hostname_handler,
m,
"sb",
hostname,
false);
if (r < 0)
return log_error_errno(r, "Could not set transient hostname: %m");
return 0;
}
static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
Manager *manager = userdata;
const sd_bus_error *e;
assert(m);
assert(manager);
e = sd_bus_message_get_error(m);
if (e)
log_warning_errno(sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message);
return 1;
}
int manager_set_timezone(Manager *m, const char *tz) {
int r;
assert(m);
assert(tz);
log_debug("Setting system timezone: '%s'", tz);
if (free_and_strdup(&m->dynamic_timezone, tz) < 0)
return log_oom();
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, setting timezone later.");
return 0;
}
r = sd_bus_call_method_async(
m->bus,
NULL,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTimezone",
set_timezone_handler,
m,
"sb",
tz,
false);
if (r < 0)
return log_error_errno(r, "Could not set timezone: %m");
return 0;
}
int manager_request_product_uuid(Manager *m, Link *link) {
int r;
assert(m);
if (m->has_product_uuid)
return 0;
log_debug("Requesting product UUID");
if (link) {
DUID *duid;
assert_se(duid = link_get_duid(link));
r = set_ensure_allocated(&m->links_requesting_uuid, NULL);
if (r < 0)
return log_oom();
r = set_ensure_allocated(&m->duids_requesting_uuid, NULL);
if (r < 0)
return log_oom();
r = set_put(m->links_requesting_uuid, link);
if (r < 0)
return log_oom();
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
}
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, requesting product UUID later.");
return 0;
}
r = sd_bus_call_method_async(
m->bus,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
"GetProductUUID",
get_product_uuid_handler,
m,
"b",
false);
if (r < 0)
return log_warning_errno(r, "Failed to get product UUID: %m");
return 0;
}