2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <netinet/in.h>
|
2014-05-18 22:10:48 +02:00
|
|
|
#include <sys/socket.h>
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <unistd.h>
|
2014-05-08 17:21:37 +02:00
|
|
|
#include <linux/if.h>
|
2017-09-14 21:51:39 +02:00
|
|
|
#include <linux/fib_rules.h>
|
2019-10-04 21:40:51 +02:00
|
|
|
#include <linux/nexthop.h>
|
2014-01-05 23:01:10 +01:00
|
|
|
|
2015-08-27 13:59:06 +02:00
|
|
|
#include "sd-daemon.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "sd-netlink.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2020-01-22 11:39:22 +01:00
|
|
|
#include "bus-polkit.h"
|
2015-02-04 15:00:20 +01:00
|
|
|
#include "bus-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "conf-parser.h"
|
2015-02-04 15:00:20 +01:00
|
|
|
#include "def.h"
|
2019-03-09 02:37:12 +01:00
|
|
|
#include "device-private.h"
|
2018-10-31 04:35:25 +01:00
|
|
|
#include "device-util.h"
|
2016-01-25 20:33:47 +01:00
|
|
|
#include "dns-domain.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.h"
|
2015-08-27 16:45:24 +02:00
|
|
|
#include "local-addresses.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "netlink-util.h"
|
2019-01-02 14:30:24 +01:00
|
|
|
#include "network-internal.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-dhcp6.h"
|
2019-05-26 22:35:02 +02:00
|
|
|
#include "networkd-link-bus.h"
|
2019-07-02 16:26:03 +02:00
|
|
|
#include "networkd-manager-bus.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-manager.h"
|
2019-06-29 22:10:35 +02:00
|
|
|
#include "networkd-network-bus.h"
|
2019-05-24 22:08:13 +02:00
|
|
|
#include "networkd-speed-meter.h"
|
2016-01-25 20:31:11 +01:00
|
|
|
#include "ordered-set.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "path-util.h"
|
|
|
|
#include "set.h"
|
2019-10-01 16:23:19 +02:00
|
|
|
#include "signal-util.h"
|
2018-10-31 04:35:25 +01:00
|
|
|
#include "strv.h"
|
2019-02-18 07:00:15 +01:00
|
|
|
#include "sysctl-util.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2019-03-04 04:19:05 +01:00
|
|
|
#include "udev-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "virt.h"
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2019-12-26 07:29:26 +01:00
|
|
|
/* use 128 MB for receive socket kernel queue. */
|
|
|
|
#define RCVBUF_SIZE (128*1024*1024)
|
2014-11-27 18:50:48 +01:00
|
|
|
|
2019-11-30 07:54:07 +01:00
|
|
|
static int log_message_warning_errno(sd_netlink_message *m, int err, const char *msg) {
|
|
|
|
const char *err_msg = NULL;
|
|
|
|
|
|
|
|
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
|
|
|
|
return log_warning_errno(err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
|
|
|
|
}
|
|
|
|
|
2014-06-18 18:22:14 +02:00
|
|
|
static int setup_default_address_pool(Manager *m) {
|
|
|
|
AddressPool *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Add in the well-known private address ranges. */
|
|
|
|
|
2019-02-20 08:58:58 +01:00
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET6, "fd00::", 8);
|
2014-06-18 18:22:14 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-02-21 06:08:46 +01:00
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
|
2014-06-18 18:22:14 +02:00
|
|
|
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;
|
|
|
|
|
2019-02-21 06:08:46 +01:00
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
|
2014-06-18 18:22:14 +02:00
|
|
|
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)
|
2015-08-26 20:43:28 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not reset carrier: %m");
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
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;
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(message);
|
2017-12-19 15:54:30 +01:00
|
|
|
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...");
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) manager_reset_all(m);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
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
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
assert(message);
|
2015-02-03 15:44:12 +01:00
|
|
|
assert(m);
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
/* 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);
|
2018-07-02 20:19:15 +02:00
|
|
|
if (m->links_requesting_uuid)
|
|
|
|
(void) manager_request_product_uuid(m, NULL);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
int manager_connect_bus(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +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)
|
2017-12-19 15:54:30 +01:00
|
|
|
return log_error_errno(r, "Failed to connect to bus: %m");
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2015-02-04 11:44:37 +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");
|
2015-02-08 13:27:56 +01:00
|
|
|
|
|
|
|
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");
|
2015-02-04 11:44:37 +01:00
|
|
|
|
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);
|
2015-02-04 11:44:37 +01:00
|
|
|
if (r < 0)
|
2017-12-18 22:10:11 +01:00
|
|
|
return log_error_errno(r, "Failed to request name: %m");
|
2015-02-04 11:44:37 +01:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
m->bus,
|
2018-07-17 05:36:02 +02:00
|
|
|
NULL,
|
2017-12-19 15:54:30 +01:00
|
|
|
"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,
|
2017-12-19 15:54:30 +01:00
|
|
|
"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");
|
2016-11-22 08:36:20 +01:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
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;
|
2015-02-03 15:44:50 +01:00
|
|
|
Link *link = NULL;
|
|
|
|
int r, ifindex;
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m);
|
|
|
|
assert(device);
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2019-03-09 02:37:12 +01:00
|
|
|
r = device_get_action(device, &action);
|
2018-10-31 04:35:25 +01:00
|
|
|
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");
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2018-10-31 04:35:25 +01:00
|
|
|
}
|
|
|
|
|
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));
|
2018-10-31 04:35:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
r = sd_device_get_ifindex(device, &ifindex);
|
2018-10-25 03:09:19 +02:00
|
|
|
if (r < 0) {
|
2018-10-31 04:35:25 +01:00
|
|
|
log_device_debug_errno(device, r, "Ignoring udev ADD event for device without ifindex or with invalid ifindex: %m");
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2015-02-01 22:13:26 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 04:19:05 +01:00
|
|
|
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));
|
2019-03-04 04:19:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r > 0) {
|
|
|
|
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = link_get(m, ifindex, &link);
|
2018-10-08 15:47:10 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENODEV)
|
|
|
|
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2018-10-08 15:47:10 +02:00
|
|
|
}
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
(void) link_initialized(link, device);
|
2017-12-21 19:07:23 +01:00
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_connect_udev(Manager *m) {
|
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
/* udev does not initialize devices inside containers,
|
|
|
|
* so we rely on them being already initialized before
|
|
|
|
* entering the container */
|
2015-09-07 13:42:47 +02:00
|
|
|
if (detect_container() > 0)
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
r = sd_device_monitor_new(&m->device_monitor);
|
2013-11-24 23:37:56 +01:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to initialize device monitor: %m");
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
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");
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-11-10 14:50:11 +01:00
|
|
|
r = sd_device_monitor_attach_event(m->device_monitor, m->event);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to attach event to device monitor: %m");
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-11-10 14:50:11 +01:00
|
|
|
r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to start device monitor: %m");
|
2014-02-18 21:42:05 +01:00
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
2019-09-09 17:16:41 +02:00
|
|
|
_cleanup_(route_freep) Route *tmp = NULL;
|
|
|
|
Route *route = NULL;
|
2015-10-25 14:46:21 +01:00
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
2019-09-09 17:16:41 +02:00
|
|
|
uint32_t ifindex;
|
2015-10-25 14:46:21 +01:00
|
|
|
uint16_t type;
|
2019-09-09 17:16:41 +02:00
|
|
|
unsigned char table;
|
2015-10-25 14:46:21 +01:00
|
|
|
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)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
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)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
|
|
|
if (r == -ENODATA) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_debug("rtnl: received route message without ifindex, ignoring");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
} else if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2019-07-07 13:34:54 +02:00
|
|
|
log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
|
2019-06-25 09:42:34 +02:00
|
|
|
return 0;
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = route_new(&tmp);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_family(message, &tmp->family);
|
2019-12-19 12:17:15 +01:00
|
|
|
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);
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0) {
|
2019-12-19 12:17:15 +01:00
|
|
|
log_warning_errno(r, "rtnl: received route message without route protocol: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
switch (tmp->family) {
|
2015-10-25 14:46:21 +01:00
|
|
|
case AF_INET:
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-06-25 09:42:34 +02:00
|
|
|
assert_not_reached("Received route message with unsupported address family");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_rtnl_message_route_get_type(message, &tmp->type);
|
2017-09-19 16:28:26 +02:00
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
|
2017-09-19 16:28:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
r = sd_rtnl_message_route_get_table(message, &table);
|
|
|
|
if (r < 0) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2019-09-09 17:16:41 +02:00
|
|
|
tmp->table = table;
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
2019-07-07 13:34:54 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:18:05 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
(void) route_get(link, tmp, &route);
|
2015-10-25 14:46:21 +01:00
|
|
|
|
2019-02-11 13:28:13 +01:00
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
|
|
|
|
*buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
|
2019-07-09 17:18:53 +02:00
|
|
|
char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
|
|
|
|
buf_protocol[ROUTE_PROTOCOL_STR_MAX];
|
2019-02-11 13:28:13 +01:00
|
|
|
|
2019-09-09 17:16:41 +02:00
|
|
|
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);
|
2019-02-11 13:28:13 +01:00
|
|
|
}
|
2019-09-09 17:16:41 +02:00
|
|
|
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);
|
2019-02-11 13:28:13 +01:00
|
|
|
|
|
|
|
log_link_debug(link,
|
2019-07-09 17:18:53 +02:00
|
|
|
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
2020-02-11 13:35:11 +01:00
|
|
|
(!route && !link->manager->manage_foreign_routes) || type == RTM_DELROUTE ? "Forgetting" :
|
|
|
|
route ? "Received remembered" : "Remembering",
|
2019-02-11 13:28:13 +01:00
|
|
|
strna(buf_dst), strempty(buf_dst_prefixlen),
|
2019-07-07 14:50:05 +02:00
|
|
|
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
|
2019-09-09 17:16:41 +02:00
|
|
|
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)));
|
2019-02-11 13:28:13 +01:00
|
|
|
}
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWROUTE:
|
2020-02-11 13:35:11 +01:00
|
|
|
if (!route && link->manager->manage_foreign_routes) {
|
2015-10-25 14:46:21 +01:00
|
|
|
/* A route appeared that we did not request */
|
2019-09-09 17:16:41 +02:00
|
|
|
r = route_add_foreign(link, tmp, &route);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
2017-12-21 19:07:23 +01:00
|
|
|
}
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELROUTE:
|
2016-05-14 22:46:01 +02:00
|
|
|
route_free(route);
|
2015-10-25 14:46:21 +01:00
|
|
|
break;
|
2016-05-14 22:46:01 +02:00
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
default:
|
2019-06-25 09:42:34 +02:00
|
|
|
assert_not_reached("Received route message with invalid RTNL message type");
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-04-19 09:53:34 +02:00
|
|
|
static int manager_rtnl_process_neighbor_lladdr(sd_netlink_message *message, union lladdr_union *lladdr, size_t *size, char **str) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(lladdr);
|
|
|
|
assert(size);
|
|
|
|
assert(str);
|
|
|
|
|
|
|
|
*str = NULL;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in6), &lladdr->ip.in6);
|
|
|
|
if (r >= 0) {
|
|
|
|
*size = sizeof(lladdr->ip.in6);
|
|
|
|
if (in_addr_to_string(AF_INET6, &lladdr->ip, str) < 0)
|
|
|
|
log_warning_errno(r, "Could not print lower address: %m");
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->mac), &lladdr->mac);
|
|
|
|
if (r >= 0) {
|
|
|
|
*size = sizeof(lladdr->mac);
|
|
|
|
*str = new(char, ETHER_ADDR_TO_STRING_MAX);
|
|
|
|
if (!*str) {
|
|
|
|
log_oom();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
ether_addr_to_string(&lladdr->mac, *str);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in), &lladdr->ip.in);
|
|
|
|
if (r >= 0) {
|
|
|
|
*size = sizeof(lladdr->ip.in);
|
|
|
|
if (in_addr_to_string(AF_INET, &lladdr->ip, str) < 0)
|
|
|
|
log_warning_errno(r, "Could not print lower address: %m");
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
|
|
|
Neighbor *neighbor = NULL;
|
|
|
|
int ifindex, family, r;
|
|
|
|
uint16_t type, state;
|
|
|
|
union in_addr_union in_addr = IN_ADDR_NULL;
|
|
|
|
_cleanup_free_ char *addr_str = NULL;
|
|
|
|
union lladdr_union lladdr;
|
|
|
|
size_t lladdr_size = 0;
|
|
|
|
_cleanup_free_ char *lladdr_str = NULL;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
|
2019-04-19 09:53:34 +02: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");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWNEIGH, RTM_DELNEIGH)) {
|
|
|
|
log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_state(message, &state);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid state, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (!FLAGS_SET(state, NUD_PERMANENT)) {
|
|
|
|
log_debug("rtnl: received non-static neighbor, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
|
|
|
log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = link_get(m, ifindex, &link);
|
|
|
|
if (r < 0 || !link) {
|
|
|
|
/* when enumerating we might be out of sync, but we will get the neighbor again, so just
|
|
|
|
* ignore it */
|
|
|
|
if (!m->enumerating)
|
|
|
|
log_warning("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_family(message, &family);
|
2019-12-19 12:17:15 +01:00
|
|
|
if (r < 0) {
|
2019-12-20 03:15:55 +01:00
|
|
|
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
|
2019-12-19 12:17:15 +01:00
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(family, AF_INET, AF_INET6)) {
|
|
|
|
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", family);
|
2019-04-19 09:53:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
r = sd_netlink_message_read_in_addr(message, NDA_DST, &in_addr.in);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, NDA_DST, &in_addr.in6);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received unsupported address family");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in_addr_to_string(family, &in_addr, &addr_str) < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not print address: %m");
|
|
|
|
|
|
|
|
r = manager_rtnl_process_neighbor_lladdr(message, &lladdr, &lladdr_size, &lladdr_str);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid lladdr, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) neighbor_get(link, family, &in_addr, &lladdr, lladdr_size, &neighbor);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWNEIGH:
|
|
|
|
if (neighbor)
|
|
|
|
log_link_debug(link, "Remembering neighbor: %s->%s",
|
|
|
|
strnull(addr_str), strnull(lladdr_str));
|
|
|
|
else {
|
|
|
|
/* A neighbor appeared that we did not request */
|
|
|
|
r = neighbor_add_foreign(link, family, &in_addr, &lladdr, lladdr_size, &neighbor);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "Failed to remember foreign neighbor %s->%s, ignoring: %m",
|
|
|
|
strnull(addr_str), strnull(lladdr_str));
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
log_link_debug(link, "Remembering foreign neighbor: %s->%s",
|
|
|
|
strnull(addr_str), strnull(lladdr_str));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELNEIGH:
|
|
|
|
if (neighbor) {
|
|
|
|
log_link_debug(link, "Forgetting neighbor: %s->%s",
|
|
|
|
strnull(addr_str), strnull(lladdr_str));
|
|
|
|
(void) neighbor_free(neighbor);
|
|
|
|
} else
|
2020-01-06 08:48:27 +01:00
|
|
|
log_link_debug(link, "Kernel removed a neighbor we don't remember: %s->%s, ignoring.",
|
|
|
|
strnull(addr_str), strnull(lladdr_str));
|
2019-04-19 09:53:34 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
2019-05-09 00:03:54 +02:00
|
|
|
_cleanup_free_ char *buf = NULL;
|
2015-09-22 17:18:20 +02:00
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
|
|
|
uint16_t type;
|
2019-05-09 00:03:54 +02:00
|
|
|
unsigned char flags, prefixlen, scope;
|
2019-05-04 20:14:08 +02:00
|
|
|
union in_addr_union in_addr = IN_ADDR_NULL;
|
2015-09-24 01:22:05 +02:00
|
|
|
struct ifa_cacheinfo cinfo;
|
|
|
|
Address *address = NULL;
|
2019-05-09 00:03:54 +02:00
|
|
|
char valid_buf[FORMAT_TIMESPAN_MAX];
|
2015-09-22 17:18:20 +02:00
|
|
|
const char *valid_str = NULL;
|
2019-05-09 00:03:54 +02:00
|
|
|
int ifindex, family, r;
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive address message, ignoring");
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
2017-09-28 08:37:38 +02:00
|
|
|
} else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received unexpected message type %u when processing address, ignoring.", type);
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
|
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received address message with invalid ifindex %d, ignoring.", ifindex);
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
2019-06-15 13:19:58 +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 address again, so just
|
|
|
|
* ignore it */
|
|
|
|
if (!m->enumerating)
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received address for link '%d' we don't know about, ignoring.", ifindex);
|
2019-06-15 13:19:58 +02:00
|
|
|
return 0;
|
2015-09-22 17:18:20 +02:00
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_family(message, &family);
|
2019-12-19 12:17:15 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning(link, "rtnl: received address message without family, ignoring.");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(family, AF_INET, AF_INET6)) {
|
|
|
|
log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", family);
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message with invalid prefixlen, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_scope(message, &scope);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message with invalid scope, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_flags(message, &flags);
|
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
switch (family) {
|
2015-09-22 17:18:20 +02:00
|
|
|
case AF_INET:
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-12-21 19:07:23 +01:00
|
|
|
assert_not_reached("Received unsupported address family");
|
2015-09-22 17:18:20 +02:00
|
|
|
}
|
|
|
|
|
2019-05-09 00:03:54 +02:00
|
|
|
r = in_addr_to_string(family, &in_addr, &buf);
|
2019-06-15 13:19:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not print address: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
|
|
|
|
return 0;
|
2019-05-09 00:03:54 +02:00
|
|
|
} 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);
|
2015-09-22 17:18:20 +02:00
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) address_get(link, family, &in_addr, prefixlen, &address);
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWADDR:
|
2015-09-28 17:16:12 +02:00
|
|
|
if (address)
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_debug(link, "Remembering updated address: %s/%u (valid %s%s)",
|
|
|
|
strnull(buf), prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-28 17:16:12 +02:00
|
|
|
else {
|
2015-09-30 14:01:44 +02:00
|
|
|
/* An address appeared that we did not request */
|
|
|
|
r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
|
2015-09-23 01:53:29 +02:00
|
|
|
if (r < 0) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m",
|
|
|
|
strnull(buf), prefixlen);
|
2015-09-23 01:53:29 +02:00
|
|
|
return 0;
|
|
|
|
} else
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_debug(link, "Remembering foreign address: %s/%u (valid %s%s)",
|
|
|
|
strnull(buf), prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-22 17:18:20 +02:00
|
|
|
}
|
|
|
|
|
2019-06-15 13:19:58 +02:00
|
|
|
/* address_update() logs internally, so we don't need to. */
|
|
|
|
(void) address_update(address, flags, scope, &cinfo);
|
2015-09-28 17:16:12 +02:00
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELADDR:
|
2015-09-24 01:22:05 +02:00
|
|
|
if (address) {
|
2019-06-15 13:19:58 +02:00
|
|
|
log_link_debug(link, "Forgetting address: %s/%u (valid %s%s)",
|
|
|
|
strnull(buf), prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) address_drop(address);
|
2015-09-22 17:18:20 +02:00
|
|
|
} else
|
2020-01-06 08:48:27 +01:00
|
|
|
log_link_debug(link, "Kernel removed an address we don't remember: %s/%u (valid %s%s), ignoring.",
|
|
|
|
strnull(buf), prefixlen,
|
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
break;
|
2019-06-15 13:19:58 +02:00
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
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) {
|
2014-04-15 14:21:44 +02:00
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
2014-05-09 17:59:20 +02:00
|
|
|
NetDev *netdev = NULL;
|
2014-05-08 18:55:11 +02:00
|
|
|
uint16_t type;
|
2014-07-18 02:35:16 +02:00
|
|
|
const char *name;
|
2014-04-15 14:21:44 +02:00
|
|
|
int r, ifindex;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(m);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
2014-12-08 19:54:06 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
2014-05-08 18:55:11 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
|
2014-05-08 18:55:11 +02:00
|
|
|
return 0;
|
2017-09-28 08:37:38 +02:00
|
|
|
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
|
2015-04-03 15:21:03 +02:00
|
|
|
return 0;
|
2014-05-08 18:55:11 +02:00
|
|
|
}
|
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
|
2014-12-08 19:54:06 +01:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
2016-01-20 01:25:45 +01:00
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
|
2014-05-09 17:59:20 +02:00
|
|
|
return 0;
|
2016-01-20 01:25:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
(void) link_get(m, ifindex, &link);
|
|
|
|
(void) netdev_get(m, name, &netdev);
|
2014-05-09 17:59:20 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWLINK:
|
|
|
|
if (!link) {
|
|
|
|
/* link is new, so add it */
|
|
|
|
r = link_add(m, message, &link);
|
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process new link message, ignoring: %m");
|
2014-05-09 17:59:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (netdev) {
|
|
|
|
/* netdev exists, so make sure the ifindex matches */
|
2014-04-15 14:21:44 +02:00
|
|
|
r = netdev_set_ifindex(netdev, message);
|
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2013-12-18 17:12:15 +01:00
|
|
|
|
2014-05-08 18:55:11 +02:00
|
|
|
r = link_update(link, message);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process link message, ignoring: %m");
|
2014-05-08 18:55:11 +02:00
|
|
|
return 0;
|
2017-12-21 19:07:23 +01:00
|
|
|
}
|
2014-05-09 17:59:20 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELLINK:
|
|
|
|
link_drop(link);
|
|
|
|
netdev_drop(netdev);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-06-25 09:42:34 +02:00
|
|
|
assert_not_reached("Received link message with invalid RTNL message type.");
|
2014-05-08 18:55:11 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
2019-06-19 06:04:24 +02:00
|
|
|
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
|
2019-08-29 21:18:27 +02:00
|
|
|
_cleanup_free_ char *from = NULL, *to = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
RoutingPolicyRule *rule = NULL;
|
2018-09-27 10:27:04 +02:00
|
|
|
const char *iif = NULL, *oif = NULL;
|
2020-02-03 00:25:48 +01:00
|
|
|
uint32_t suppress_prefixlen;
|
2017-09-14 21:51:39 +02:00
|
|
|
Manager *m = userdata;
|
2019-06-19 06:04:24 +02:00
|
|
|
unsigned flags;
|
2017-09-14 21:51:39 +02:00
|
|
|
uint16_t type;
|
|
|
|
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)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: received unexpected message type %u when processing rule, ignoring.", type);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = routing_policy_rule_new(&tmp);
|
|
|
|
if (r < 0) {
|
|
|
|
log_oom();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_get_family(message, &tmp->family);
|
2017-09-27 17:55:13 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
|
2017-09-27 17:55:13 +02:00
|
|
|
return 0;
|
2019-06-19 06:04:24 +02:00
|
|
|
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_debug("rtnl: received rule message with invalid family %d, ignoring.", tmp->family);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
switch (tmp->family) {
|
2017-09-14 21:51:39 +02:00
|
|
|
case AF_INET:
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, FRA_SRC, &tmp->from.in);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
|
2017-12-21 19:07:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, FRA_DST, &tmp->to.in);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
|
2017-12-21 19:07:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &tmp->from.in6);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
|
2017-12-21 19:07:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, FRA_DST, &tmp->to.in6);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
|
2017-12-21 19:07:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-06-25 09:42:34 +02:00
|
|
|
assert_not_reached("Received rule message with unsupported address family");
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
if (tmp->from_prefixlen == 0 && tmp->to_prefixlen == 0)
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
|
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
|
2019-06-19 06:04:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
tmp->invert_rule = flags & FIB_RULE_INVERT;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 10:27:04 +02:00
|
|
|
r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-19 06:04:24 +02:00
|
|
|
r = free_and_strdup(&tmp->iif, iif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2017-12-21 19:07:23 +01:00
|
|
|
|
2018-09-27 10:27:04 +02:00
|
|
|
r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-19 06:04:24 +02:00
|
|
|
r = free_and_strdup(&tmp->oif, oif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
|
2018-11-27 06:28:54 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
|
2018-11-27 06:28:54 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
|
2018-11-27 06:28:54 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-26 14:22:38 +01:00
|
|
|
r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-03 00:25:48 +01:00
|
|
|
r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_PREFIXLEN, &suppress_prefixlen);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_PREFIXLEN attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r >= 0)
|
|
|
|
tmp->suppress_prefixlen = (int) suppress_prefixlen;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
(void) routing_policy_rule_get(m, tmp, &rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-08-29 21:18:27 +02:00
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->from, &from);
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->to, &to);
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWRULE:
|
2017-12-02 01:49:52 +01:00
|
|
|
if (!rule) {
|
2019-08-29 21:18:27 +02:00
|
|
|
log_debug("Remembering foreign routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
|
|
|
|
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
|
2019-06-19 06:04:24 +02:00
|
|
|
r = routing_policy_rule_add_foreign(m, tmp, &rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTM_DELRULE:
|
2019-08-29 21:18:27 +02:00
|
|
|
log_debug("Forgetting routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
|
|
|
|
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
|
2017-09-14 21:51:39 +02:00
|
|
|
routing_policy_rule_free(rule);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:40:51 +02:00
|
|
|
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
|
|
|
_cleanup_(nexthop_freep) NextHop *tmp = NULL;
|
|
|
|
_cleanup_free_ char *gateway = NULL;
|
|
|
|
NextHop *nexthop = NULL;
|
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
|
|
|
uint16_t type;
|
|
|
|
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)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
|
2019-10-04 21:40:51 +02: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");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWNEXTHOP, RTM_DELNEXTHOP)) {
|
|
|
|
log_warning("rtnl: received unexpected message type %u when processing nexthop, ignoring.", type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = nexthop_new(&tmp);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_rtnl_message_get_family(message, &tmp->family);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get nexthop family, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
|
|
|
log_debug("rtnl: received nexthop message with invalid family %d, ignoring.", tmp->family);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (tmp->family) {
|
|
|
|
case AF_INET:
|
|
|
|
r = sd_netlink_message_read_in_addr(message, NHA_GATEWAY, &tmp->gw.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, NHA_GATEWAY, &tmp->gw.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received rule message with unsupported address family");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, NHA_ID, &tmp->id);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get NHA_ID attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, NHA_OIF, &tmp->oif);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = link_get(m, tmp->oif, &link);
|
|
|
|
if (r < 0 || !link) {
|
|
|
|
if (!m->enumerating)
|
|
|
|
log_warning("rtnl: received nexthop message for link (%d) we do not know about, ignoring", tmp->oif);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) nexthop_get(link, tmp, &nexthop);
|
|
|
|
|
|
|
|
if (DEBUG_LOGGING)
|
|
|
|
(void) in_addr_to_string(tmp->family, &tmp->gw, &gateway);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWNEXTHOP:
|
|
|
|
if (!nexthop) {
|
|
|
|
log_debug("Remembering foreign nexthop: %s, oif: %d, id: %d", gateway, tmp->oif, tmp->id);
|
|
|
|
r = nexthop_add_foreign(link, tmp, &nexthop);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Could not remember foreign nexthop, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTM_DELNEXTHOP:
|
|
|
|
log_debug("Forgetting foreign nexthop: %s, oif: %d, id: %d", gateway, tmp->oif, tmp->id);
|
|
|
|
nexthop_free(nexthop);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_connect_rtnl(Manager *m) {
|
|
|
|
int fd, r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
fd = systemd_netlink_fd();
|
|
|
|
if (fd < 0)
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&m->rtnl);
|
2015-02-03 15:44:50 +01:00
|
|
|
else
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open_fd(&m->rtnl, fd);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
2013-12-18 03:37:26 +01:00
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-04-19 09:53:34 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
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;
|
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
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;
|
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-10-15 10:49:53 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-04 21:40:51 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2014-12-08 19:54:06 +01:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2016-11-18 17:04:26 +01:00
|
|
|
static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
|
2015-09-30 18:17:43 +02:00
|
|
|
char *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2016-11-18 17:04:26 +01:00
|
|
|
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);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
r = ordered_set_consume(s, p);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r == -EEXIST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-12-14 16:25:01 +01:00
|
|
|
static int ordered_set_put_in4_addrv(OrderedSet *s,
|
|
|
|
const struct in_addr *addresses,
|
|
|
|
size_t n,
|
|
|
|
bool (*predicate)(const struct in_addr *addr)) {
|
2016-11-18 17:04:26 +01:00
|
|
|
int r, c = 0;
|
2018-12-14 16:25:01 +01:00
|
|
|
size_t i;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
assert(s);
|
2016-11-18 17:04:26 +01:00
|
|
|
assert(n == 0 || addresses);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2018-12-14 16:25:01 +01:00
|
|
|
if (predicate && !predicate(&addresses[i]))
|
|
|
|
continue;
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in4_addr(s, addresses+i);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
c += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_save(Manager *m) {
|
2019-09-18 15:22:47 +02:00
|
|
|
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
|
|
|
|
const char *operstate_str, *carrier_state_str, *address_state_str;
|
2015-09-30 18:17:43 +02:00
|
|
|
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
|
2019-06-09 22:22:25 +02:00
|
|
|
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
|
|
|
|
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
|
2019-09-18 15:22:47 +02:00
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
|
|
|
_cleanup_strv_free_ char **p = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
2015-09-30 18:17:43 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->state_file);
|
|
|
|
|
|
|
|
/* We add all NTP and DNS server to a set, to filter out duplicates */
|
2016-01-25 20:31:11 +01:00
|
|
|
dns = ordered_set_new(&string_hash_ops);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!dns)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
ntp = ordered_set_new(&string_hash_ops);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!ntp)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-09-18 15:22:47 +02:00
|
|
|
sip = ordered_set_new(&string_hash_ops);
|
|
|
|
if (!sip)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:33:47 +01:00
|
|
|
search_domains = ordered_set_new(&dns_name_hash_ops);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (!search_domains)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:33:47 +01:00
|
|
|
route_domains = ordered_set_new(&dns_name_hash_ops);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (!route_domains)
|
2015-09-30 18:17:43 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(link, m->links, i) {
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->operstate > operstate)
|
|
|
|
operstate = link->operstate;
|
|
|
|
|
2019-06-09 22:22:25 +02:00
|
|
|
if (link->carrier_state > carrier_state)
|
|
|
|
carrier_state = link->carrier_state;
|
|
|
|
|
|
|
|
if (link->address_state > address_state)
|
|
|
|
address_state = link->address_state;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!link->network)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* First add the static configured entries */
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!link->dhcp_lease)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Secondly, add the entries acquired via DHCP */
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_dns) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2018-12-14 16:25:01 +01:00
|
|
|
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_ntp) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2018-12-14 16:25:01 +01:00
|
|
|
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-09-18 15:22:47 +02:00
|
|
|
if (link->network->dhcp_use_sip) {
|
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
|
|
|
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const char *domainname;
|
2017-05-13 16:19:32 +02:00
|
|
|
char **domains = NULL;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2017-05-13 16:19:32 +02:00
|
|
|
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
|
2015-09-30 18:17:43 +02:00
|
|
|
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
|
|
|
|
if (r >= 0) {
|
2017-05-13 16:19:32 +02:00
|
|
|
r = ordered_set_put_strdup(target_domains, domainname);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r != -ENODATA)
|
|
|
|
return r;
|
2016-01-25 22:27:01 +01:00
|
|
|
|
2017-05-13 16:19:32 +02:00
|
|
|
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = ordered_set_put_strdupv(target_domains, domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 22:22:25 +02:00
|
|
|
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
|
|
|
|
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
operstate_str = link_operstate_to_string(operstate);
|
|
|
|
assert(operstate_str);
|
|
|
|
|
2019-06-09 21:56:03 +02:00
|
|
|
carrier_state_str = link_carrier_state_to_string(carrier_state);
|
|
|
|
assert(carrier_state_str);
|
|
|
|
|
|
|
|
address_state_str = link_address_state_to_string(address_state);
|
|
|
|
assert(address_state_str);
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
r = fopen_temporary(m->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-11-18 17:04:26 +01:00
|
|
|
(void) fchmod(fileno(f), 0644);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"# This is private data. Do not parse.\n"
|
2019-06-09 21:56:03 +02:00
|
|
|
"OPER_STATE=%s\n"
|
|
|
|
"CARRIER_STATE=%s\n"
|
|
|
|
"ADDRESS_STATE=%s\n",
|
|
|
|
operstate_str, carrier_state_str, address_state_str);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-02-20 22:39:47 +01:00
|
|
|
ordered_set_print(f, "DNS=", dns);
|
|
|
|
ordered_set_print(f, "NTP=", ntp);
|
2019-09-18 15:22:47 +02:00
|
|
|
ordered_set_print(f, "SIP=", sip);
|
2019-02-20 22:39:47 +01:00
|
|
|
ordered_set_print(f, "DOMAINS=", search_domains);
|
|
|
|
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
r = routing_policy_serialize_rules(m->rules, f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
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;
|
2019-06-09 22:22:25 +02:00
|
|
|
if (strv_extend(&p, "OperationalState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->carrier_state != carrier_state) {
|
|
|
|
m->carrier_state = carrier_state;
|
|
|
|
if (strv_extend(&p, "CarrierState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->address_state != address_state) {
|
|
|
|
m->address_state = address_state;
|
|
|
|
if (strv_extend(&p, "AddressState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
r = manager_send_changed_strv(m, p);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
2019-06-09 22:22:25 +02:00
|
|
|
log_error_errno(r, "Could not emit changed properties: %m");
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_clean(link);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-10-01 16:23:19 +02:00
|
|
|
static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
m->restarting = false;
|
|
|
|
|
|
|
|
log_debug("Terminate operation initiated.");
|
|
|
|
|
|
|
|
return sd_event_exit(sd_event_source_get_event(s), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
m->restarting = true;
|
|
|
|
|
|
|
|
log_debug("Restart operation initiated.");
|
|
|
|
|
|
|
|
return sd_event_exit(sd_event_source_get_event(s), 0);
|
|
|
|
}
|
|
|
|
|
2018-07-18 05:37:50 +02:00
|
|
|
int manager_new(Manager **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_(manager_freep) Manager *m = NULL;
|
2014-12-08 19:54:06 +01:00
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
m = new(Manager, 1);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (!m)
|
|
|
|
return -ENOMEM;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
*m = (Manager) {
|
|
|
|
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
|
2020-02-11 13:35:11 +01:00
|
|
|
.manage_foreign_routes = true,
|
2019-05-24 22:08:13 +02:00
|
|
|
};
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->state_file = strdup("/run/systemd/netif/state");
|
|
|
|
if (!m->state_file)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-07-18 05:37:50 +02:00
|
|
|
r = sd_event_default(&m->event);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-01 16:23:19 +02:00
|
|
|
assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
|
|
|
|
|
2018-07-20 04:29:49 +02:00
|
|
|
(void) sd_event_set_watchdog(m->event, true);
|
2019-10-01 16:23:19 +02:00
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
|
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
|
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = manager_connect_rtnl(m);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
r = manager_connect_genl(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = manager_connect_udev(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
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;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = setup_default_address_pool(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
networkd: rework duid_{type,duid_type,duid,duid_len} setting
Separate fields are replaced with a struct.
Second second duid type field is removed. The first field was used to carry
the result of DUIDType= configuration, and the second was either a copy of
this, or contained the type extracted from DuidRawData. The semantics are changed
so that the type specified in DUIDType is always used. DUIDRawData= no longer
overrides the type setting.
The networkd code is now more constrained than the sd-dhcp code:
DUIDRawData cannot have 0 length, length 0 is treated the same as unsetting.
Likewise, it is not possible to set a DUIDType=0. If it ever becomes necessary
to set type=0 or a zero-length duid, the code can be changed to support that.
Nevertheless, I think that's unlikely.
This addresses #3127 § 1 and 3.
v2:
- rename DUID.duid, DUID.duid_len to DUID.raw_data, DUID.raw_data_len
2016-04-29 05:23:45 +02:00
|
|
|
m->duid.type = DUID_TYPE_EN;
|
2016-03-31 01:33:55 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
(void) routing_policy_load_rules(m->state_file, &m->rules_saved);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(m);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
void manager_free(Manager *m) {
|
2019-05-04 19:43:45 +02:00
|
|
|
struct in6_addr *a;
|
2018-11-04 12:36:13 +01:00
|
|
|
AddressPool *pool;
|
2015-02-03 15:44:50 +01:00
|
|
|
Link *link;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
if (!m)
|
|
|
|
return;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
free(m->state_file);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2019-05-04 19:43:45 +02:00
|
|
|
while ((a = hashmap_first_key(m->dhcp6_prefixes)))
|
2019-06-29 21:09:51 +02:00
|
|
|
(void) dhcp6_prefix_remove(m, a);
|
2019-07-17 03:21:07 +02:00
|
|
|
m->dhcp6_prefixes = hashmap_free(m->dhcp6_prefixes);
|
2018-01-04 14:11:58 +01:00
|
|
|
|
2018-11-12 07:33:18 +01:00
|
|
|
while ((link = hashmap_steal_first(m->links))) {
|
2018-09-19 02:32:30 +02:00
|
|
|
if (link->dhcp6_client)
|
2018-11-12 07:33:18 +01:00
|
|
|
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
|
2019-05-06 16:06:50 +02:00
|
|
|
|
2019-06-03 19:05:26 +02:00
|
|
|
(void) link_stop_clients(link, true);
|
2019-05-06 16:06:50 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
link_unref(link);
|
2018-09-19 02:32:30 +02:00
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-11-04 12:36:13 +01:00
|
|
|
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
2019-04-15 09:38:45 +02:00
|
|
|
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
|
|
|
|
m->links = hashmap_free_with_destructor(m->links, link_unref);
|
2018-07-02 20:19:15 +02:00
|
|
|
|
2019-04-15 09:38:45 +02:00
|
|
|
m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
|
2019-05-04 13:02:18 +02:00
|
|
|
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
|
2015-02-08 13:29:35 +01:00
|
|
|
|
2018-11-04 12:36:13 +01:00
|
|
|
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
|
|
|
while ((pool = m->address_pools))
|
|
|
|
address_pool_free(pool);
|
|
|
|
|
2018-11-01 12:21:26 +01:00
|
|
|
/* 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);
|
2017-11-28 13:02:33 +01:00
|
|
|
set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-05-02 11:52:03 +02:00
|
|
|
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);
|
2015-08-27 17:38:05 +02:00
|
|
|
sd_event_unref(m->event);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
sd_device_monitor_unref(m->device_monitor);
|
2015-10-09 21:36:04 +02:00
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
2019-01-17 15:53:15 +01:00
|
|
|
sd_bus_flush_close_unref(m->bus);
|
2015-10-09 21:36:04 +02:00
|
|
|
|
2016-11-22 08:36:20 +01:00
|
|
|
free(m->dynamic_timezone);
|
|
|
|
free(m->dynamic_hostname);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
free(m);
|
|
|
|
}
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
int manager_start(Manager *m) {
|
2015-09-30 18:17:43 +02:00
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
2019-05-24 22:08:13 +02:00
|
|
|
int r;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
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");
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
/* 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);
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
return 0;
|
2015-02-04 15:00:20 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
int manager_load_config(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* update timestamp */
|
2019-01-02 14:30:24 +01:00
|
|
|
paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2019-09-02 14:48:08 +02:00
|
|
|
r = netdev_load(m, false);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-23 15:20:48 +02:00
|
|
|
r = network_load(m, &m->networks);
|
2014-08-28 15:46:29 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
bool manager_should_reload(Manager *m) {
|
2019-01-02 14:30:24 +01:00
|
|
|
return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false);
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int manager_rtnl_enumerate_links(Manager *m) {
|
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, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *link;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
assert(m);
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m->rtnl);
|
2014-07-01 10:09:52 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
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);
|
2013-12-03 18:48:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
2014-05-08 18:55:11 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (link = reply; link; link = sd_netlink_message_next(link)) {
|
2015-02-03 15:44:50 +01:00
|
|
|
int k;
|
2014-05-10 19:39:03 +02:00
|
|
|
|
2015-02-04 10:08:12 +01:00
|
|
|
m->enumerating = true;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
k = manager_rtnl_process_link(m->rtnl, link, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
2015-02-04 10:08:12 +01:00
|
|
|
|
|
|
|
m->enumerating = false;
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
2014-05-10 19:39:03 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
return r;
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
2014-01-05 23:01:10 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
int manager_rtnl_enumerate_addresses(Manager *m) {
|
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, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *addr;
|
2014-01-13 23:48:28 +01:00
|
|
|
int r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
2014-01-18 01:37:35 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-18 01:37:35 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-01-13 23:48:28 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
|
2015-02-03 15:44:50 +01:00
|
|
|
int k;
|
|
|
|
|
2015-02-04 10:08:12 +01:00
|
|
|
m->enumerating = true;
|
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
k = manager_rtnl_process_address(m->rtnl, addr, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
2015-02-04 10:08:12 +01:00
|
|
|
|
|
|
|
m->enumerating = false;
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
2014-01-13 23:48:28 +01:00
|
|
|
}
|
2019-04-19 09:53:34 +02:00
|
|
|
|
|
|
|
int manager_rtnl_enumerate_neighbors(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
sd_netlink_message *neigh;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC);
|
|
|
|
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 (neigh = reply; neigh; neigh = sd_netlink_message_next(neigh)) {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
m->enumerating = true;
|
|
|
|
|
|
|
|
k = manager_rtnl_process_neighbor(m->rtnl, neigh, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
m->enumerating = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
int manager_rtnl_enumerate_routes(Manager *m) {
|
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, *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;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
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
|
|
|
}
|
2017-09-14 21:51:39 +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;
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:40:51 +02:00
|
|
|
int manager_rtnl_enumerate_nexthop(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
sd_netlink_message *nexthop;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 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) {
|
|
|
|
if (r == -EOPNOTSUPP) {
|
|
|
|
log_debug("Nexthop are not supported by the kernel. Ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nexthop = reply; nexthop; nexthop = sd_netlink_message_next(nexthop)) {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
m->enumerating = true;
|
|
|
|
|
|
|
|
k = manager_rtnl_process_nexthop(m->rtnl, nexthop, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
m->enumerating = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
|
2014-06-18 18:22:14 +02:00
|
|
|
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;
|
|
|
|
}
|
2015-08-27 16:45:24 +02:00
|
|
|
|
|
|
|
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.");
|
2015-08-27 16:45:24 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link == exclude)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->operstate < LINK_OPERSTATE_ROUTABLE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
void manager_dirty(Manager *manager) {
|
|
|
|
assert(manager);
|
|
|
|
|
|
|
|
/* the serialized state in /run is no longer up-to-date */
|
|
|
|
manager->dirty = true;
|
|
|
|
}
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
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));
|
2017-12-19 15:54:30 +01:00
|
|
|
|
2016-11-22 08:36:20 +01:00
|
|
|
if (free_and_strdup(&m->dynamic_hostname, hostname) < 0)
|
|
|
|
return log_oom();
|
2016-11-21 23:15:41 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
|
2018-07-23 20:22:28 +02:00
|
|
|
log_debug("Not connected to system bus, setting hostname later.");
|
2016-11-21 23:15:41 +01:00
|
|
|
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);
|
2016-11-22 08:36:20 +01:00
|
|
|
if (free_and_strdup(&m->dynamic_timezone, tz) < 0)
|
|
|
|
return log_oom();
|
2016-11-21 23:15:41 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
|
2018-07-23 20:22:28 +02:00
|
|
|
log_debug("Not connected to system bus, setting timezone later.");
|
2016-11-21 23:15:41 +01:00
|
|
|
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;
|
|
|
|
}
|
2018-07-02 20:19:15 +02:00
|
|
|
|
|
|
|
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();
|
2019-08-11 02:11:20 +02:00
|
|
|
|
|
|
|
link_ref(link);
|
2018-07-02 20:19:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|