NetworkManager/src/nm-iface-helper.c

682 lines
23 KiB
C
Raw Normal View History

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2014 Red Hat, Inc.
*/
#include "nm-default.h"
#include <glib-unix.h>
#include <getopt.h>
#include <locale.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <signal.h>
#include <linux/rtnetlink.h>
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
#include "nm-utils/nm-c-list.h"
#include "main-utils.h"
#include "NetworkManagerUtils.h"
#include "platform/nm-linux-platform.h"
#include "platform/nm-platform-utils.h"
#include "dhcp/nm-dhcp-manager.h"
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
#include "nm-utils.h"
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
#include "nm-setting-ip6-config.h"
#include "systemd/nm-sd.h"
#if !defined(NM_DIST_VERSION)
# define NM_DIST_VERSION VERSION
#endif
#define NMIH_PID_FILE_FMT NMRUNDIR "/nm-iface-helper-%d.pid"
/*****************************************************************************/
static struct {
GMainLoop *main_loop;
int ifindex;
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
guint dad_failed_id;
CList dad_failed_lst_head;
} gl/*obal*/ = {
.ifindex = -1,
};
static struct {
gboolean slaac;
gboolean show_version;
gboolean become_daemon;
gboolean debug;
gboolean g_fatal_warnings;
gboolean slaac_required;
gboolean dhcp4_required;
int tempaddr;
char *ifname;
char *uuid;
char *stable_id;
char *dhcp4_address;
char *dhcp4_clientid;
char *dhcp4_hostname;
char *dhcp4_fqdn;
char *iid_str;
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
char *logging_backend;
char *opt_log_level;
char *opt_log_domains;
guint32 priority_v4;
guint32 priority_v6;
} global_opt = {
.tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
.priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
.priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
};
/*****************************************************************************/
2016-10-05 12:04:46 +02:00
#define _NMLOG_PREFIX_NAME "nm-iface-helper"
#define _NMLOG(level, domain, ...) \
2017-03-02 21:17:22 +01:00
nm_log ((level), (domain), global_opt.ifname, NULL, \
2016-10-05 15:34:06 +02:00
"iface-helper: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \
2016-10-05 12:04:46 +02:00
_NM_UTILS_MACRO_REST (__VA_ARGS__))
/*****************************************************************************/
static void
dhcp4_state_changed (NMDhcpClient *client,
NMDhcpState state,
NMIP4Config *ip4_config,
GHashTable *options,
const char *event_id,
gpointer user_data)
{
static NMIP4Config *last_config = NULL;
NMIP4Config *existing;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
2016-10-05 12:04:46 +02:00
_LOGD (LOGD_DHCP4, "new DHCPv4 client state %d", state);
switch (state) {
case NM_DHCP_STATE_BOUND:
g_assert (ip4_config);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
g_assert (nm_ip4_config_get_ifindex (ip4_config) == gl.ifindex);
existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex);
if (last_config)
nm_ip4_config_subtract (existing, last_config, 0);
nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
nm_ip4_config_add_dependent_routes (existing,
RT_TABLE_MAIN,
global_opt.priority_v4,
&ip4_dev_route_blacklist);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if (!nm_ip4_config_commit (existing,
NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN))
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config");
nm_platform_ip4_dev_route_blacklist_set (NM_PLATFORM_GET,
gl.ifindex,
ip4_dev_route_blacklist);
if (last_config)
g_object_unref (last_config);
last_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_dhcp_client_get_ifindex (client));
nm_ip4_config_replace (last_config, ip4_config, NULL);
break;
case NM_DHCP_STATE_TIMEOUT:
case NM_DHCP_STATE_DONE:
case NM_DHCP_STATE_FAIL:
if (global_opt.dhcp4_required) {
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_DHCP4, "DHCPv4 timed out or failed, quitting...");
g_main_loop_quit (gl.main_loop);
} else
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_DHCP4, "DHCPv4 timed out or failed");
break;
default:
break;
}
}
static void
ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, gpointer user_data)
{
NMNDiscConfigMap changed = changed_int;
static NMIP6Config *ndisc_config = NULL;
NMIP6Config *existing;
existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, global_opt.tempaddr);
if (ndisc_config)
nm_ip6_config_subtract (existing, ndisc_config, 0);
else {
ndisc_config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
gl.ifindex);
}
if (changed & NM_NDISC_CONFIG_ADDRESSES) {
guint8 plen;
guint32 ifa_flags;
/* Check, whether kernel is recent enough to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address. */
ifa_flags = 0;
if (nm_platform_check_kernel_support (NM_PLATFORM_GET,
NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
if (NM_IN_SET (global_opt.tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR))
ifa_flags |= IFA_F_MANAGETEMPADDR;
plen = 64;
} else
plen = 128;
nm_ip6_config_reset_addresses_ndisc (ndisc_config,
rdata->addresses,
rdata->addresses_n,
plen,
ifa_flags);
}
if (NM_FLAGS_ANY (changed, NM_NDISC_CONFIG_ROUTES
| NM_NDISC_CONFIG_GATEWAYS)) {
nm_ip6_config_reset_routes_ndisc (ndisc_config,
rdata->gateways,
rdata->gateways_n,
rdata->routes,
rdata->routes_n,
RT_TABLE_MAIN,
global_opt.priority_v6,
nm_platform_check_kernel_support (NM_PLATFORM_GET,
NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF));
}
if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) {
/* Unsupported until systemd DHCPv6 is ready */
}
if (changed & NM_NDISC_CONFIG_HOP_LIMIT)
nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, global_opt.ifname, rdata->hop_limit);
if (changed & NM_NDISC_CONFIG_MTU) {
char val[16];
char sysctl_path_buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
g_snprintf (val, sizeof (val), "%d", rdata->mtu);
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, sysctl_path_buf, global_opt.ifname, "mtu")), val);
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
nm_ip6_config_add_dependent_routes (existing,
RT_TABLE_MAIN,
global_opt.priority_v6);
if (!nm_ip6_config_commit (existing,
NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
NULL))
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}
static void
ndisc_ra_timeout (NMNDisc *ndisc, gpointer user_data)
{
if (global_opt.slaac_required) {
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_IP6, "IPv6 timed out or failed, quitting...");
g_main_loop_quit (gl.main_loop);
} else
2016-10-05 12:04:46 +02:00
_LOGW (LOGD_IP6, "IPv6 timed out or failed");
}
static gboolean
quit_handler (gpointer user_data)
{
g_main_loop_quit (gl.main_loop);
return G_SOURCE_REMOVE;
}
static void
setup_signals (void)
{
signal (SIGPIPE, SIG_IGN);
g_unix_signal_add (SIGINT, quit_handler, NULL);
g_unix_signal_add (SIGTERM, quit_handler, NULL);
}
static gboolean
do_early_setup (int *argc, char **argv[])
{
gint64 priority64_v4 = -1;
gint64 priority64_v6 = -1;
GOptionEntry options[] = {
/* Interface/IP config */
{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &global_opt.ifname, N_("The interface to manage"), "eth0" },
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &global_opt.uuid, N_("Connection UUID"), "661e8cd0-b618-46b8-9dc9-31a52baaa16b" },
{ "stable-id", '\0', 0, G_OPTION_ARG_STRING, &global_opt.stable_id, N_("Connection Token for Stable IDs"), "eth" },
{ "slaac", 's', 0, G_OPTION_ARG_NONE, &global_opt.slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &global_opt.slaac_required, N_("Whether SLAAC must be successful"), NULL },
{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &global_opt.tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_address, N_("Current DHCPv4 address"), NULL },
{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &global_opt.dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
{ "dhcp4-fqdn", 'F', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_fqdn, N_("FQDN to send to DHCP server"), N_("host.domain.org") },
{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), "" },
core: add support for RFC7217 stable privacy addressing RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
2015-10-03 19:44:27 +02:00
{ "addr-gen-mode", 'e', 0, G_OPTION_ARG_INT, &global_opt.addr_gen_mode, N_("IPv6 SLAAC address generation mode"), "eui64" },
{ "logging-backend", '\0', 0, G_OPTION_ARG_STRING, &global_opt.logging_backend, N_("The logging backend configuration value. See logging.backend in NetworkManager.conf"), NULL },
/* Logging/debugging */
{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
{ "debug", 'b', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
"PLATFORM,RFKILL,WIFI" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &global_opt.g_fatal_warnings, N_("Make all warnings fatal"), NULL },
{NULL}
};
if (!nm_main_utils_early_setup ("nm-iface-helper",
argc,
argv,
options,
NULL,
NULL,
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
return FALSE;
if (priority64_v4 >= 0 && priority64_v4 <= G_MAXUINT32)
global_opt.priority_v4 = (guint32) priority64_v4;
if (priority64_v6 >= 0 && priority64_v6 <= G_MAXUINT32)
global_opt.priority_v6 = (guint32) priority64_v6;
return TRUE;
}
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
typedef struct {
NMPlatform *platform;
NMNDisc *ndisc;
} DadFailedHandleData;
static gboolean
dad_failed_handle_idle (gpointer user_data)
{
DadFailedHandleData *data = user_data;
NMCListElem *elem;
while ((elem = c_list_first_entry (&gl.dad_failed_lst_head, NMCListElem, lst))) {
nm_auto_nmpobj const NMPObject *obj = elem->data;
nm_c_list_elem_free (elem);
if (nm_ndisc_dad_addr_is_fail_candidate (data->platform, obj)) {
nm_ndisc_dad_failed (data->ndisc,
&NMP_OBJECT_CAST_IP6_ADDRESS (obj)->address,
TRUE);
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
}
}
gl.dad_failed_id = 0;
return G_SOURCE_REMOVE;
}
static void
ip6_address_changed (NMPlatform *platform,
int obj_type_i,
int iface,
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
const NMPlatformIP6Address *addr,
int change_type_i,
NMNDisc *ndisc)
{
const NMPlatformSignalChangeType change_type = change_type_i;
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
DadFailedHandleData *data;
if (!nm_ndisc_dad_addr_is_fail_candidate_event (change_type, addr))
return;
c_list_link_tail (&gl.dad_failed_lst_head,
&nm_c_list_elem_new_stale ((gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr)))->lst);
if (gl.dad_failed_id)
return;
data = g_slice_new (DadFailedHandleData);
data->platform = platform;
data->ndisc = ndisc;
gl.dad_failed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
dad_failed_handle_idle,
data,
nm_g_slice_free_fcn (DadFailedHandleData));
}
int
main (int argc, char *argv[])
{
char *bad_domains = NULL;
GError *error = NULL;
gboolean wrote_pidfile = FALSE;
gs_free char *pidfile = NULL;
gs_unref_object NMDhcpClient *dhcp4_client = NULL;
gs_unref_object NMNDisc *ndisc = NULL;
gs_unref_bytes GBytes *hwaddr = NULL;
gs_unref_bytes GBytes *client_id = NULL;
gs_free NMUtilsIPv6IfaceId *iid = NULL;
guint sd_id;
char sysctl_path_buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
c_list_init (&gl.dad_failed_lst_head);
setpgid (getpid (), getpid ());
if (!do_early_setup (&argc, &argv))
return 1;
nm_logging_set_syslog_identifier ("nm-iface-helper");
2016-10-05 15:34:06 +02:00
nm_logging_set_prefix ("%s[%ld] (%s): ",
_NMLOG_PREFIX_NAME,
(long) getpid (),
global_opt.ifname ?: "???");
if (global_opt.g_fatal_warnings) {
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
if (global_opt.show_version) {
fprintf (stdout, NM_DIST_VERSION "\n");
return 0;
}
nm_main_utils_ensure_root ();
if (!global_opt.ifname || !global_opt.uuid) {
fprintf (stderr, _("An interface name and UUID are required\n"));
return 1;
}
gl.ifindex = nmp_utils_if_nametoindex (global_opt.ifname);
if (gl.ifindex <= 0) {
fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, strerror (errno));
return 1;
}
pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, gl.ifindex);
nm_main_utils_ensure_not_running_pidfile (pidfile);
nm_main_utils_ensure_rundir ();
if (!nm_logging_setup (global_opt.opt_log_level,
global_opt.opt_log_domains,
&bad_domains,
&error)) {
fprintf (stderr,
_("%s. Please use --help to see a list of valid options.\n"),
error->message);
return 1;
} else if (bad_domains) {
fprintf (stderr,
_("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
bad_domains);
g_clear_pointer (&bad_domains, g_free);
}
if (global_opt.become_daemon && !global_opt.debug) {
if (daemon (0, 0) < 0) {
int saved_errno;
saved_errno = errno;
fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
g_strerror (saved_errno),
saved_errno);
return 1;
}
if (nm_main_utils_write_pidfile (pidfile))
wrote_pidfile = TRUE;
}
/* Set up unix signal handling - before creating threads, but after daemonizing! */
gl.main_loop = g_main_loop_new (NULL, FALSE);
setup_signals ();
nm_logging_syslog_openlog (global_opt.logging_backend,
global_opt.debug);
2016-10-05 12:04:46 +02:00
_LOGI (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
/* Set up platform interaction layer */
nm_linux_platform_setup ();
hwaddr = nm_platform_link_get_address_as_bytes (NM_PLATFORM_GET, gl.ifindex);
if (global_opt.iid_str) {
GBytes *bytes;
gsize ignored = 0;
bytes = nm_utils_hexstr2bin (global_opt.iid_str);
if (!bytes || g_bytes_get_size (bytes) != sizeof (*iid)) {
fprintf (stderr, _("(%s): Invalid IID %s\n"), global_opt.ifname, global_opt.iid_str);
return 1;
}
iid = g_bytes_unref_to_data (bytes, &ignored);
}
if (global_opt.dhcp4_clientid) {
/* this string is just a plain hex-string. Unlike ipv4.dhcp-client-id, which
* is parsed via nm_dhcp_utils_client_id_string_to_bytes(). */
client_id = nm_utils_hexstr2bin (global_opt.dhcp4_clientid);
if (!client_id || g_bytes_get_size (client_id) < 2) {
fprintf (stderr, _("(%s): Invalid DHCP client-id %s\n"), global_opt.ifname, global_opt.dhcp4_clientid);
return 1;
}
}
if (global_opt.dhcp4_address) {
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, sysctl_path_buf, global_opt.ifname, "promote_secondaries")), "1");
dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
nm_platform_get_multi_idx (NM_PLATFORM_GET),
global_opt.ifname,
gl.ifindex,
hwaddr,
global_opt.uuid,
RT_TABLE_MAIN,
global_opt.priority_v4,
!!global_opt.dhcp4_hostname,
global_opt.dhcp4_hostname,
global_opt.dhcp4_fqdn,
client_id,
NM_DHCP_TIMEOUT_DEFAULT,
NULL,
global_opt.dhcp4_address);
g_assert (dhcp4_client);
g_signal_connect (dhcp4_client,
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
G_CALLBACK (dhcp4_state_changed),
NULL);
}
if (global_opt.slaac) {
NMUtilsStableType stable_type = NM_UTILS_STABLE_TYPE_UUID;
const char *stable_id = global_opt.uuid;
nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, gl.ifindex, TRUE);
if ( global_opt.stable_id
&& (global_opt.stable_id[0] >= '0' && global_opt.stable_id[0] <= '9')
&& global_opt.stable_id[1] == ' ') {
/* strict parsing of --stable-id, which is the numeric stable-type
* and the ID, joined with one space. For now, only support stable-types
* from 0 to 9. */
stable_type = (global_opt.stable_id[0] - '0');
stable_id = &global_opt.stable_id[2];
}
ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, gl.ifindex, global_opt.ifname,
stable_type, stable_id,
global_opt.addr_gen_mode,
NM_NDISC_NODE_TYPE_HOST,
NULL);
g_assert (ndisc);
if (iid)
nm_ndisc_set_iid (ndisc, *iid);
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, sysctl_path_buf, global_opt.ifname, "accept_ra")), "1");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, sysctl_path_buf, global_opt.ifname, "accept_ra_defrtr")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, sysctl_path_buf, global_opt.ifname, "accept_ra_pinfo")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, sysctl_path_buf, global_opt.ifname, "accept_ra_rtr_pref")), "0");
g_signal_connect (NM_PLATFORM_GET,
NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
G_CALLBACK (ip6_address_changed),
ndisc);
g_signal_connect (ndisc,
NM_NDISC_CONFIG_RECEIVED,
G_CALLBACK (ndisc_config_changed),
NULL);
g_signal_connect (ndisc,
NM_NDISC_RA_TIMEOUT,
G_CALLBACK (ndisc_ra_timeout),
NULL);
nm_ndisc_start (ndisc);
}
sd_id = nm_sd_event_attach_default ();
g_main_loop_run (gl.main_loop);
iface-helper: fix non-reentrant call to platform for failed IPv6 DAD Platform invokes change events while reading netlink events. However, platform code is not re-entrant and calling into platform again is not allowed (aside operations that do not process the netlink socket, like lookup of the platform cache). That basically means, we have to always process events in an idle handler. That is not a too strong limitation, because we anyway don't know the call context in which the platform event is emitted and we should avoid unguarded recursive calls into platform. Otherwise, we get hit an assertion/crash in nm-iface-helper: 1 raise() 2 abort() 3 g_assertion_message() 4 g_assertion_message_expr() 5 do_delete_object() 6 ip6_address_delete() >>> 7 nm_platform_ip6_address_delete() 8 nm_platform_ip6_address_sync() 9 nm_ip6_config_commit() 10 ndisc_config_changed() 11 ffi_call_unix64() 12 ffi_call() 13 g_cclosure_marshal_generic_va() 14 _g_closure_invoke_va() 15 g_signal_emit_valist() 16 g_signal_emit() >>> 17 nm_ndisc_dad_failed() 18 ffi_call_unix64() 19 ffi_call() 20 g_cclosure_marshal_generic() 21 g_closure_invoke() 22 signal_emit_unlocked_R() 23 g_signal_emit_valist() 24 g_signal_emit() >>> 25 nm_platform_cache_update_emit_signal() 26 event_handler_recvmsgs() 27 event_handler_read_netlink() 28 delayed_action_handle_one() 29 delayed_action_handle_all() 30 do_delete_object() 31 ip6_address_delete() 32 nm_platform_ip6_address_delete() 33 nm_platform_ip6_address_sync() >>> 34 nm_ip6_config_commit() 35 ndisc_config_changed() 36 ffi_call_unix64() 37 ffi_call() 38 g_cclosure_marshal_generic_va() 39 _g_closure_invoke_va() 40 g_signal_emit_valist() 41 g_signal_emit() 42 check_timestamps() 43 receive_ra() 44 ndp_call_eventfd_handler() 45 ndp_callall_eventfd_handler() 46 event_ready() 47 g_main_context_dispatch() 48 g_main_context_iterate.isra.22() 49 g_main_loop_run() >>> 50 main() NMPlatform already has a check to assert against recursive calls in delayed_action_handle_all(): g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; ... priv->delayed_action.is_handling--; Fixes: f85728ecff824b1fece43aba51d8171db2766ea2 https://bugzilla.redhat.com/show_bug.cgi?id=1546656
2018-02-19 16:13:06 +01:00
nm_clear_g_source (&gl.dad_failed_id);
nm_c_list_elem_free_all (&gl.dad_failed_lst_head, (GDestroyNotify) nmp_object_unref);
if (pidfile && wrote_pidfile)
unlink (pidfile);
2016-10-05 12:04:46 +02:00
_LOGI (LOGD_CORE, "exiting");
nm_clear_g_source (&sd_id);
g_clear_pointer (&gl.main_loop, g_main_loop_unref);
return 0;
}
/*****************************************************************************/
const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = {
&_nm_dhcp_client_factory_internal,
};
/*****************************************************************************/
/* Stub functions */
#include "nm-config.h"
#include "devices/nm-device.h"
#include "nm-active-connection.h"
#include "nm-dbus-manager.h"
void
nm_main_config_reload (int signal)
{
2016-10-05 12:04:46 +02:00
_LOGI (LOGD_CORE, "reloading configuration not supported");
}
NMConfig *
nm_config_get (void)
{
return GUINT_TO_POINTER (1);
}
NMConfigData *
nm_config_get_data_orig (NMConfig *config)
{
return GUINT_TO_POINTER (1);
}
char *
nm_config_data_get_value (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags)
{
return NULL;
}
gboolean
nm_config_get_configure_and_quit (NMConfig *config)
{
return TRUE;
}
core/dbus: rework D-Bus implementation to use lower layer GDBusConnection API Previously, we used the generated GDBusInterfaceSkeleton types and glued them via the NMExportedObject base class to our NM types. We also used GDBusObjectManagerServer. Don't do that anymore. The resulting code was more complicated despite (or because?) using generated classes. It was hard to understand, complex, had ordering-issues, and had a runtime and memory overhead. This patch refactors this entirely and uses the lower layer API GDBusConnection directly. It replaces the generated code, GDBusInterfaceSkeleton, and GDBusObjectManagerServer. All this is now done by NMDbusObject and NMDBusManager and static descriptor instances of type GDBusInterfaceInfo. This adds a net plus of more then 1300 lines of hand written code. I claim that this implementation is easier to understand. Note that previously we also required extensive and complex glue code to bind our objects to the generated skeleton objects. Instead, now glue our objects directly to GDBusConnection. The result is more immediate and gets rid of layers of code in between. Now that the D-Bus glue us more under our control, we can address issus and bottlenecks better, instead of adding code to bend the generated skeletons to our needs. Note that the current implementation now only supports one D-Bus connection. That was effectively the case already, although there were places (and still are) where the code pretends it could also support connections from a private socket. We dropped private socket support mainly because it was unused, untested and buggy, but also because GDBusObjectManagerServer could not export the same objects on multiple connections. Now, it would be rather straight forward to fix that and re-introduce ObjectManager on each private connection. But this commit doesn't do that yet, and the new code intentionally supports only one D-Bus connection. Also, the D-Bus startup was simplified. There is no retry, either nm_dbus_manager_start() succeeds, or it detects the initrd case. In the initrd case, bus manager never tries to connect to D-Bus. Since the initrd scenario is not yet used/tested, this is good enough for the moment. It could be easily extended later, for example with polling whether the system bus appears (like was done previously). Also, restart of D-Bus daemon isn't supported either -- just like before. Note how NMDBusManager now implements the ObjectManager D-Bus interface directly. Also, this fixes race issues in the server, by no longer delaying PropertiesChanged signals. NMExportedObject would collect changed properties and send the signal out in idle_emit_properties_changed() on idle. This messes up the ordering of change events w.r.t. other signals and events on the bus. Note that not only NMExportedObject messed up the ordering. Also the generated code would hook into notify() and process change events in and idle handle, exhibiting the same ordering issue too. No longer do that. PropertiesChanged signals will be sent right away by hooking into dispatch_properties_changed(). This means, changing a property in quick succession will no longer be combined and is guaranteed to emit signals for each individual state. Quite possibly we emit now more PropertiesChanged signals then before. However, we are now able to group a set of changes by using standard g_object_freeze_notify()/g_object_thaw_notify(). We probably should make more use of that. Also, now that our signals are all handled in the right order, we might find places where we still emit them in the wrong order. But that is then due to the order in which our GObjects emit signals, not due to an ill behavior of the D-Bus glue. Possibly we need to identify such ordering issues and fix them. Numbers (for contrib/rpm --without debug on x86_64): - the patch changes the code size of NetworkManager by - 2809360 bytes + 2537528 bytes (-9.7%) - Runtime measurements are harder because there is a large variance during testing. In other words, the numbers are not reproducible. Currently, the implementation performs no caching of GVariants at all, but it would be rather simple to add it, if that turns out to be useful. Anyway, without strong claim, it seems that the new form tends to perform slightly better. That would be no surprise. $ time (for i in {1..1000}; do nmcli >/dev/null || break; echo -n .; done) - real 1m39.355s + real 1m37.432s $ time (for i in {1..2000}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects > /dev/null || break; echo -n .; done) - real 0m26.843s + real 0m25.281s - Regarding RSS size, just looking at the processes in similar conditions, doesn't give a large difference. On my system they consume about 19MB RSS. It seems that the new version has a slightly smaller RSS size. - 19356 RSS + 18660 RSS
2018-02-26 13:51:52 +01:00
NMDBusManager *
nm_dbus_manager_get (void)
{
return NULL;
}
gboolean
nm_dbus_manager_is_stopping (NMDBusManager *self)
{
return FALSE;
}
core/dbus: rework D-Bus implementation to use lower layer GDBusConnection API Previously, we used the generated GDBusInterfaceSkeleton types and glued them via the NMExportedObject base class to our NM types. We also used GDBusObjectManagerServer. Don't do that anymore. The resulting code was more complicated despite (or because?) using generated classes. It was hard to understand, complex, had ordering-issues, and had a runtime and memory overhead. This patch refactors this entirely and uses the lower layer API GDBusConnection directly. It replaces the generated code, GDBusInterfaceSkeleton, and GDBusObjectManagerServer. All this is now done by NMDbusObject and NMDBusManager and static descriptor instances of type GDBusInterfaceInfo. This adds a net plus of more then 1300 lines of hand written code. I claim that this implementation is easier to understand. Note that previously we also required extensive and complex glue code to bind our objects to the generated skeleton objects. Instead, now glue our objects directly to GDBusConnection. The result is more immediate and gets rid of layers of code in between. Now that the D-Bus glue us more under our control, we can address issus and bottlenecks better, instead of adding code to bend the generated skeletons to our needs. Note that the current implementation now only supports one D-Bus connection. That was effectively the case already, although there were places (and still are) where the code pretends it could also support connections from a private socket. We dropped private socket support mainly because it was unused, untested and buggy, but also because GDBusObjectManagerServer could not export the same objects on multiple connections. Now, it would be rather straight forward to fix that and re-introduce ObjectManager on each private connection. But this commit doesn't do that yet, and the new code intentionally supports only one D-Bus connection. Also, the D-Bus startup was simplified. There is no retry, either nm_dbus_manager_start() succeeds, or it detects the initrd case. In the initrd case, bus manager never tries to connect to D-Bus. Since the initrd scenario is not yet used/tested, this is good enough for the moment. It could be easily extended later, for example with polling whether the system bus appears (like was done previously). Also, restart of D-Bus daemon isn't supported either -- just like before. Note how NMDBusManager now implements the ObjectManager D-Bus interface directly. Also, this fixes race issues in the server, by no longer delaying PropertiesChanged signals. NMExportedObject would collect changed properties and send the signal out in idle_emit_properties_changed() on idle. This messes up the ordering of change events w.r.t. other signals and events on the bus. Note that not only NMExportedObject messed up the ordering. Also the generated code would hook into notify() and process change events in and idle handle, exhibiting the same ordering issue too. No longer do that. PropertiesChanged signals will be sent right away by hooking into dispatch_properties_changed(). This means, changing a property in quick succession will no longer be combined and is guaranteed to emit signals for each individual state. Quite possibly we emit now more PropertiesChanged signals then before. However, we are now able to group a set of changes by using standard g_object_freeze_notify()/g_object_thaw_notify(). We probably should make more use of that. Also, now that our signals are all handled in the right order, we might find places where we still emit them in the wrong order. But that is then due to the order in which our GObjects emit signals, not due to an ill behavior of the D-Bus glue. Possibly we need to identify such ordering issues and fix them. Numbers (for contrib/rpm --without debug on x86_64): - the patch changes the code size of NetworkManager by - 2809360 bytes + 2537528 bytes (-9.7%) - Runtime measurements are harder because there is a large variance during testing. In other words, the numbers are not reproducible. Currently, the implementation performs no caching of GVariants at all, but it would be rather simple to add it, if that turns out to be useful. Anyway, without strong claim, it seems that the new form tends to perform slightly better. That would be no surprise. $ time (for i in {1..1000}; do nmcli >/dev/null || break; echo -n .; done) - real 1m39.355s + real 1m37.432s $ time (for i in {1..2000}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects > /dev/null || break; echo -n .; done) - real 0m26.843s + real 0m25.281s - Regarding RSS size, just looking at the processes in similar conditions, doesn't give a large difference. On my system they consume about 19MB RSS. It seems that the new version has a slightly smaller RSS size. - 19356 RSS + 18660 RSS
2018-02-26 13:51:52 +01:00
void
_nm_dbus_manager_obj_export (NMDBusObject *obj)
{
}
void
_nm_dbus_manager_obj_unexport (NMDBusObject *obj)
{
}
void
core/dbus: rework D-Bus implementation to use lower layer GDBusConnection API Previously, we used the generated GDBusInterfaceSkeleton types and glued them via the NMExportedObject base class to our NM types. We also used GDBusObjectManagerServer. Don't do that anymore. The resulting code was more complicated despite (or because?) using generated classes. It was hard to understand, complex, had ordering-issues, and had a runtime and memory overhead. This patch refactors this entirely and uses the lower layer API GDBusConnection directly. It replaces the generated code, GDBusInterfaceSkeleton, and GDBusObjectManagerServer. All this is now done by NMDbusObject and NMDBusManager and static descriptor instances of type GDBusInterfaceInfo. This adds a net plus of more then 1300 lines of hand written code. I claim that this implementation is easier to understand. Note that previously we also required extensive and complex glue code to bind our objects to the generated skeleton objects. Instead, now glue our objects directly to GDBusConnection. The result is more immediate and gets rid of layers of code in between. Now that the D-Bus glue us more under our control, we can address issus and bottlenecks better, instead of adding code to bend the generated skeletons to our needs. Note that the current implementation now only supports one D-Bus connection. That was effectively the case already, although there were places (and still are) where the code pretends it could also support connections from a private socket. We dropped private socket support mainly because it was unused, untested and buggy, but also because GDBusObjectManagerServer could not export the same objects on multiple connections. Now, it would be rather straight forward to fix that and re-introduce ObjectManager on each private connection. But this commit doesn't do that yet, and the new code intentionally supports only one D-Bus connection. Also, the D-Bus startup was simplified. There is no retry, either nm_dbus_manager_start() succeeds, or it detects the initrd case. In the initrd case, bus manager never tries to connect to D-Bus. Since the initrd scenario is not yet used/tested, this is good enough for the moment. It could be easily extended later, for example with polling whether the system bus appears (like was done previously). Also, restart of D-Bus daemon isn't supported either -- just like before. Note how NMDBusManager now implements the ObjectManager D-Bus interface directly. Also, this fixes race issues in the server, by no longer delaying PropertiesChanged signals. NMExportedObject would collect changed properties and send the signal out in idle_emit_properties_changed() on idle. This messes up the ordering of change events w.r.t. other signals and events on the bus. Note that not only NMExportedObject messed up the ordering. Also the generated code would hook into notify() and process change events in and idle handle, exhibiting the same ordering issue too. No longer do that. PropertiesChanged signals will be sent right away by hooking into dispatch_properties_changed(). This means, changing a property in quick succession will no longer be combined and is guaranteed to emit signals for each individual state. Quite possibly we emit now more PropertiesChanged signals then before. However, we are now able to group a set of changes by using standard g_object_freeze_notify()/g_object_thaw_notify(). We probably should make more use of that. Also, now that our signals are all handled in the right order, we might find places where we still emit them in the wrong order. But that is then due to the order in which our GObjects emit signals, not due to an ill behavior of the D-Bus glue. Possibly we need to identify such ordering issues and fix them. Numbers (for contrib/rpm --without debug on x86_64): - the patch changes the code size of NetworkManager by - 2809360 bytes + 2537528 bytes (-9.7%) - Runtime measurements are harder because there is a large variance during testing. In other words, the numbers are not reproducible. Currently, the implementation performs no caching of GVariants at all, but it would be rather simple to add it, if that turns out to be useful. Anyway, without strong claim, it seems that the new form tends to perform slightly better. That would be no surprise. $ time (for i in {1..1000}; do nmcli >/dev/null || break; echo -n .; done) - real 1m39.355s + real 1m37.432s $ time (for i in {1..2000}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects > /dev/null || break; echo -n .; done) - real 0m26.843s + real 0m25.281s - Regarding RSS size, just looking at the processes in similar conditions, doesn't give a large difference. On my system they consume about 19MB RSS. It seems that the new version has a slightly smaller RSS size. - 19356 RSS + 18660 RSS
2018-02-26 13:51:52 +01:00
_nm_dbus_manager_obj_notify (NMDBusObject *obj,
guint n_pspecs,
const GParamSpec *const*pspecs)
{
}
void
core/dbus: rework D-Bus implementation to use lower layer GDBusConnection API Previously, we used the generated GDBusInterfaceSkeleton types and glued them via the NMExportedObject base class to our NM types. We also used GDBusObjectManagerServer. Don't do that anymore. The resulting code was more complicated despite (or because?) using generated classes. It was hard to understand, complex, had ordering-issues, and had a runtime and memory overhead. This patch refactors this entirely and uses the lower layer API GDBusConnection directly. It replaces the generated code, GDBusInterfaceSkeleton, and GDBusObjectManagerServer. All this is now done by NMDbusObject and NMDBusManager and static descriptor instances of type GDBusInterfaceInfo. This adds a net plus of more then 1300 lines of hand written code. I claim that this implementation is easier to understand. Note that previously we also required extensive and complex glue code to bind our objects to the generated skeleton objects. Instead, now glue our objects directly to GDBusConnection. The result is more immediate and gets rid of layers of code in between. Now that the D-Bus glue us more under our control, we can address issus and bottlenecks better, instead of adding code to bend the generated skeletons to our needs. Note that the current implementation now only supports one D-Bus connection. That was effectively the case already, although there were places (and still are) where the code pretends it could also support connections from a private socket. We dropped private socket support mainly because it was unused, untested and buggy, but also because GDBusObjectManagerServer could not export the same objects on multiple connections. Now, it would be rather straight forward to fix that and re-introduce ObjectManager on each private connection. But this commit doesn't do that yet, and the new code intentionally supports only one D-Bus connection. Also, the D-Bus startup was simplified. There is no retry, either nm_dbus_manager_start() succeeds, or it detects the initrd case. In the initrd case, bus manager never tries to connect to D-Bus. Since the initrd scenario is not yet used/tested, this is good enough for the moment. It could be easily extended later, for example with polling whether the system bus appears (like was done previously). Also, restart of D-Bus daemon isn't supported either -- just like before. Note how NMDBusManager now implements the ObjectManager D-Bus interface directly. Also, this fixes race issues in the server, by no longer delaying PropertiesChanged signals. NMExportedObject would collect changed properties and send the signal out in idle_emit_properties_changed() on idle. This messes up the ordering of change events w.r.t. other signals and events on the bus. Note that not only NMExportedObject messed up the ordering. Also the generated code would hook into notify() and process change events in and idle handle, exhibiting the same ordering issue too. No longer do that. PropertiesChanged signals will be sent right away by hooking into dispatch_properties_changed(). This means, changing a property in quick succession will no longer be combined and is guaranteed to emit signals for each individual state. Quite possibly we emit now more PropertiesChanged signals then before. However, we are now able to group a set of changes by using standard g_object_freeze_notify()/g_object_thaw_notify(). We probably should make more use of that. Also, now that our signals are all handled in the right order, we might find places where we still emit them in the wrong order. But that is then due to the order in which our GObjects emit signals, not due to an ill behavior of the D-Bus glue. Possibly we need to identify such ordering issues and fix them. Numbers (for contrib/rpm --without debug on x86_64): - the patch changes the code size of NetworkManager by - 2809360 bytes + 2537528 bytes (-9.7%) - Runtime measurements are harder because there is a large variance during testing. In other words, the numbers are not reproducible. Currently, the implementation performs no caching of GVariants at all, but it would be rather simple to add it, if that turns out to be useful. Anyway, without strong claim, it seems that the new form tends to perform slightly better. That would be no surprise. $ time (for i in {1..1000}; do nmcli >/dev/null || break; echo -n .; done) - real 1m39.355s + real 1m37.432s $ time (for i in {1..2000}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects > /dev/null || break; echo -n .; done) - real 0m26.843s + real 0m25.281s - Regarding RSS size, just looking at the processes in similar conditions, doesn't give a large difference. On my system they consume about 19MB RSS. It seems that the new version has a slightly smaller RSS size. - 19356 RSS + 18660 RSS
2018-02-26 13:51:52 +01:00
_nm_dbus_manager_obj_emit_signal (NMDBusObject *obj,
const NMDBusInterfaceInfoExtended *interface_info,
const GDBusSignalInfo *signal_info,
GVariant *args)
{
}
dbus: fix emitting D-Bus NetworkManager's old-style PropertiesChange signal Before switching to gdbus (before 1.2.0), NetworkManager used dbus-glib. Most objects in the D-Bus API with properties had a signal NetworkManager-specific "PropertiesChanged" signal. Nowadays, this way of handling of property changes is deprecated for the common "PropertiesChanged" signal on the "org.freedesktop.DBus.Properties" interface. There were a few pecularities in 1.0.0 and earlier: (1) Due to the implementation with dbus-glib, a property-changed signal was emitted on *all* interfaces. For example: - a change on a NMDeviceVeth of "NMDeviceEthernet.HwAddress" would be emitted both for the interfaces "fdo.NM.Device.Ethernet" and "fdo.NM.Device.Veth". Note that NMDeviceVeth is derived from NMDeviceEthernet and there is no "HwAddress" on veth device. - a change of "NMVpnConnection.VpnState" was emitted on both interfaces "fdo.NM.VPN.Connection" and "fdo.NM.Connecion.Active". Note that NMActiveConnection is the parent type of NMVpnConnection and only the latter has a property "VpnState". (2) NMDevice's "fdo.NM.Device" interface doesn't have a "PropertiesChanged" signal. From (1) follows that all property-changes for this type were instead invoked with an interface like "fdo.NM.Device.Ethernet" (or multiple interfaces in case of NMDeviceVeth). 1.2.0 introduced gdbus, which gives us the standard "fdo.DBus.Properties" signal. However, it made the mistake of not realizing (1), thus instead of emitting the signal once for each interface, it would pick the first one in the inheritance tree. With 1.4.0, a bug from merge commit 844345e caused signals for devices to be only emitted for the interface "fdo.NM.Device.Statistics", instead of "fdo.NM.Device.Ethernet" or "fdo.NM.Device.Veth" (or both). The latter is what bgo#770629 is about and what commit 82e9439 tried to fix. However, the fix was wrong because it tried to do the theoretically correct thing of emitting the property-changed signal exactly once for the interface that actually ontains the property. In addition, it missed that NMDevice doesn't have a PropertiesChanged signal, which caused signals for "fdo.NM.Device" to get lost *sigh*. Now, restore the (broken) behavior of 1.0.0. These old-style property changed signals are anyway considered deprecated and exist solely to satisfy old clients and preserve the old API. Fixes: 63fbfad3705db5901e6a2a6a2fc332da0f0ae4be https://bugzilla.gnome.org/show_bug.cgi?id=770629 https://bugzilla.redhat.com/show_bug.cgi?id=1371920
2016-09-01 13:00:21 +02:00
GType
nm_device_get_type (void)
{
g_return_val_if_reached (0);
}
GType
nm_active_connection_get_type (void)
{
g_return_val_if_reached (0);
}