device: merge branch 'th/device-mtu-rh1414901'

https://bugzilla.redhat.com/show_bug.cgi?id=1414901
This commit is contained in:
Thomas Haller
2017-10-24 16:07:49 +02:00
14 changed files with 338 additions and 172 deletions

View File

@@ -32,6 +32,7 @@
#include <libintl.h>
#include <gmodule.h>
#include <sys/stat.h>
#include <net/if.h>
#if WITH_JANSSON
#include <jansson.h>
@@ -3675,36 +3676,41 @@ _nm_utils_generate_mac_address_mask_parse (const char *value,
gboolean
nm_utils_is_valid_iface_name (const char *name, GError **error)
{
g_return_val_if_fail (name != NULL, FALSE);
int i;
if (*name == '\0') {
g_return_val_if_fail (name, FALSE);
if (name[0] == '\0') {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name is too short"));
return FALSE;
}
if (strlen (name) >= 16) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name is longer than 15 characters"));
return FALSE;
}
if (!strcmp (name, ".") || !strcmp (name, "..")) {
if ( name[0] == '.'
&& ( name[1] == '\0'
|| ( name[1] == '.'
&& name[2] == '\0'))) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name is reserved"));
return FALSE;
}
while (*name) {
if (*name == '/' || g_ascii_isspace (*name)) {
for (i = 0; i < IFNAMSIZ; i++) {
char ch = name[i];
if (ch == '\0')
return TRUE;
if ( NM_IN_SET (ch, '/', ':')
|| g_ascii_isspace (ch)) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name contains an invalid character"));
return FALSE;
}
name++;
}
return TRUE;
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name is longer than 15 characters"));
return FALSE;
}
/**

View File

@@ -118,6 +118,8 @@ gint64 nm_device_get_configured_mtu_from_connection_default (NMDevice *self,
guint32 nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_config);
void nm_device_commit_mtu (NMDevice *self);
/*****************************************************************************/
#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \

View File

@@ -51,6 +51,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceVlan,
typedef struct {
gulong parent_state_id;
gulong parent_hwaddr_id;
gulong parent_mtu_id;
guint vlan_id;
} NMDeviceVlanPrivate;
@@ -85,6 +86,17 @@ parent_state_changed (NMDevice *parent,
nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
}
static void
parent_mtu_maybe_changed (NMDevice *parent,
GParamSpec *pspec,
gpointer user_data)
{
/* the MTU of a VLAN device is limited by the parent's MTU.
*
* When the parent's MTU changes, try to re-set the MTU. */
nm_device_commit_mtu (user_data);
}
static void
parent_hwaddr_maybe_changed (NMDevice *parent,
GParamSpec *pspec,
@@ -143,6 +155,7 @@ parent_changed_notify (NMDevice *device,
* parent_changed_notify(). */
nm_clear_g_signal_handler (old_parent, &priv->parent_state_id);
nm_clear_g_signal_handler (old_parent, &priv->parent_hwaddr_id);
nm_clear_g_signal_handler (old_parent, &priv->parent_mtu_id);
if (new_parent) {
priv->parent_state_id = g_signal_connect (new_parent,
@@ -154,6 +167,10 @@ parent_changed_notify (NMDevice *device,
G_CALLBACK (parent_hwaddr_maybe_changed), device);
parent_hwaddr_maybe_changed (new_parent, NULL, self);
priv->parent_mtu_id = g_signal_connect (new_parent, "notify::" NM_DEVICE_MTU,
G_CALLBACK (parent_mtu_maybe_changed), device);
parent_mtu_maybe_changed (new_parent, NULL, self);
/* Set parent-dependent unmanaged flag */
nm_device_set_unmanaged_by_flags (device,
NM_UNMANAGED_PARENT,
@@ -482,8 +499,10 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
/* Change MAC address to parent's one if needed */
parent_device = nm_device_parent_get_device (device);
if (parent_device)
if (parent_device) {
parent_hwaddr_maybe_changed (parent_device, NULL, device);
parent_mtu_maybe_changed (parent_device, NULL, device);
}
s_vlan = (NMSettingVlan *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_VLAN);
if (s_vlan) {

View File

@@ -72,6 +72,7 @@
#include "nm-arping-manager.h"
#include "nm-connectivity.h"
#include "nm-dbus-interface.h"
#include "nm-device-vlan.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
@@ -550,6 +551,7 @@ static void realize_start_setup (NMDevice *self,
const char *assume_state_connection_uuid,
gboolean set_nm_owned,
NMUnmanFlagOp unmanaged_user_explicit);
static void _set_mtu (NMDevice *self, guint32 mtu);
static void _commit_mtu (NMDevice *self, const NMIP4Config *config);
static void dhcp_schedule_restart (NMDevice *self, int addr_family, const char *reason);
static void _cancel_activation (NMDevice *self);
@@ -851,26 +853,29 @@ nm_device_ipv4_sysctl_set (NMDevice *self, const char *property, const char *val
NMPlatform *platform = nm_device_get_platform (self);
gs_free char *value_to_free = NULL;
const char *value_to_set;
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
if (value) {
value_to_set = value;
} else {
/* Set to a default value when we've got a NULL @value. */
value_to_free = nm_platform_sysctl_get (platform,
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path ("default", property)));
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, "default", property)));
value_to_set = value_to_free;
}
return nm_platform_sysctl_set (platform,
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, nm_device_get_ip_iface (self), property)),
value_to_set);
}
static guint32
nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, nm_device_get_ip_iface (self), property)),
10,
0,
G_MAXUINT32,
@@ -880,14 +885,18 @@ nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32
gboolean
nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
{
return nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), value);
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, buf, nm_device_get_ip_iface (self), property)), value);
}
static guint32
nm_device_ipv6_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, buf, nm_device_get_ip_iface (self), property)),
10,
0,
G_MAXUINT32,
@@ -2672,10 +2681,7 @@ device_link_changed (NMDevice *self)
_notify (self, PROP_DRIVER);
}
if (priv->mtu != info.mtu) {
priv->mtu = info.mtu;
_notify (self, PROP_MTU);
}
_set_mtu (self, info.mtu);
if (ifindex == nm_device_get_ip_ifindex (self))
_stats_update_counters_from_pllink (self, &info);
@@ -3242,7 +3248,6 @@ realize_start_setup (NMDevice *self,
NMDeviceCapabilities capabilities = 0;
NMConfig *config;
guint real_rate;
guint32 mtu;
/* plink is a NMPlatformLink type, however, we require it to come from the platform
* cache (where else would it come from?). */
@@ -3271,10 +3276,7 @@ realize_start_setup (NMDevice *self,
priv->mtu_initial = 0;
priv->ip6_mtu_initial = 0;
priv->ip6_mtu = 0;
if (priv->mtu) {
priv->mtu = 0;
_notify (self, PROP_MTU);
}
_set_mtu (self, 0);
_assume_state_set (self, assume_state_guess_assume, assume_state_connection_uuid);
@@ -3295,11 +3297,9 @@ realize_start_setup (NMDevice *self,
if (nm_platform_link_is_software (nm_device_get_platform (self), priv->ifindex))
capabilities |= NM_DEVICE_CAP_IS_SOFTWARE;
mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), priv->ifindex);
if (priv->mtu != mtu) {
priv->mtu = mtu;
_notify (self, PROP_MTU);
}
_set_mtu (self,
nm_platform_link_get_mtu (nm_device_get_platform (self),
priv->ifindex));
nm_platform_link_get_driver_info (nm_device_get_platform (self),
priv->ifindex,
@@ -3524,10 +3524,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
if (nm_clear_g_free (&priv->ip_iface))
_notify (self, PROP_IP_IFACE);
if (priv->mtu != 0) {
priv->mtu = 0;
_notify (self, PROP_MTU);
}
_set_mtu (self, 0);
if (priv->driver_version) {
g_clear_pointer (&priv->driver_version, g_free);
@@ -7211,6 +7208,26 @@ nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_co
/*****************************************************************************/
static void
_set_mtu (NMDevice *self, guint32 mtu)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->mtu == mtu)
return;
priv->mtu = mtu;
_notify (self, PROP_MTU);
if (priv->master) {
/* changing the MTU of a slave, might require the master to reset
* it's MTU. Note that the master usually cannot set a MTU larger
* then the slave's. Hence, when the slave increases the MTU,
* master might want to retry setting the MTU. */
nm_device_commit_mtu (priv->master);
}
}
static void
_commit_mtu (NMDevice *self, const NMIP4Config *config)
{
@@ -7230,8 +7247,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
return;
if (nm_device_sys_iface_state_is_external_or_assume (self)) {
/* for assumed connections we don't tamper with the MTU. This is
* a bug and supposed to be fixed by the unmanaged/assumed rework. */
/* for assumed connections we don't tamper with the MTU. */
return;
}
@@ -7331,6 +7347,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
})
if ( (mtu_desired && mtu_desired != mtu_plat)
|| (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ())) {
gboolean anticipated_failure = FALSE;
if (!priv->mtu_initial && !priv->ip6_mtu_initial) {
/* before touching any of the MTU paramters, record the
@@ -7340,19 +7357,52 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
}
if (mtu_desired && mtu_desired != mtu_plat) {
nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired);
if (nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired) == NM_PLATFORM_ERROR_CANT_SET_MTU) {
anticipated_failure = TRUE;
_LOGW (LOGD_DEVICE, "mtu: failure to set MTU. %s",
NM_IS_DEVICE_VLAN (self)
? "Is the parent's MTU size large enough?"
: (!c_list_is_empty (&priv->slaves)
? "Are the MTU sizes of the slaves large enough?"
: "Did you configure the MTU correctly?"));
}
priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS;
}
if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ()) {
nm_device_ipv6_sysctl_set (self, "mtu",
nm_sprintf_buf (sbuf, "%u", (unsigned) ip6_mtu));
if (!nm_device_ipv6_sysctl_set (self, "mtu",
nm_sprintf_buf (sbuf, "%u", (unsigned) ip6_mtu))) {
int errsv = errno;
_NMLOG (anticipated_failure && errsv == EINVAL ? LOGL_DEBUG : LOGL_WARN,
LOGD_DEVICE,
"mtu: failure to set IPv6 MTU%s",
anticipated_failure && errsv == EINVAL
? ": Is the underlying MTU value successfully set?"
: "");
}
priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS;
}
}
#undef _IP6_MTU_SYS
}
void
nm_device_commit_mtu (NMDevice *self)
{
NMDeviceState state;
g_return_if_fail (NM_IS_DEVICE (self));
state = nm_device_get_state (self);
if ( state >= NM_DEVICE_STATE_CONFIG
&& state < NM_DEVICE_STATE_DEACTIVATING) {
_LOGT (LOGD_DEVICE, "mtu: commit-mtu...");
_commit_mtu (self, NM_DEVICE_GET_PRIVATE (self)->ip4_config);
} else
_LOGT (LOGD_DEVICE, "mtu: commit-mtu... skip due to state %s", nm_device_state_to_str (state));
}
static void
ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self)
{
@@ -7654,7 +7704,9 @@ save_ip6_properties (NMDevice *self)
g_hash_table_remove_all (priv->ip6_saved_properties);
for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) {
value = nm_platform_sysctl_get (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i])));
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
value = nm_platform_sysctl_get (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, buf, ifname, ip6_properties_to_save[i])));
if (value) {
g_hash_table_insert (priv->ip6_saved_properties,
(char *) ip6_properties_to_save[i],
@@ -7714,9 +7766,11 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
}
if (enable) {
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
/* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
value = nm_platform_sysctl_get (nm_device_get_platform (self),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6")));
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, buf, nm_device_get_ip_iface (self), "disable_ipv6")));
if (g_strcmp0 (value, "0") == 0)
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
g_free (value);

View File

@@ -531,8 +531,10 @@ start (NMNDisc *ndisc)
static inline int
ipv6_sysctl_get (NMPlatform *platform, const char *ifname, const char *property, int min, int max, int defval)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return (int) nm_platform_sysctl_get_int_checked (platform,
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, property)),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET6, buf, ifname, property)),
10,
min,
max,

View File

@@ -2525,55 +2525,88 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_
#define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/"
#define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/"
G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR));
G_STATIC_ASSERT (NM_STRLEN (IPV6_PROPERTY_DIR) + IFNAMSIZ + 60 == NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE);
static const char *
_get_property_path (const char *ifname,
const char *property,
gboolean ipv6)
/**
* nm_utils_sysctl_ip_conf_path:
* @addr_family: either AF_INET or AF_INET6.
* @buf: the output buffer where to write the path. It
* must be at least NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE bytes
* long.
* @ifname: an interface name
* @property: a property name
*
* Returns: the path to IPv6 property @property on @ifname. Note that
* this returns the input argument @buf.
*/
const char *
nm_utils_sysctl_ip_conf_path (int addr_family, char *buf, const char *ifname, const char *property)
{
static char path[sizeof (IPV6_PROPERTY_DIR) + IFNAMSIZ + 32];
int len;
ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
nm_assert (buf);
nm_assert_addr_family (addr_family);
g_assert (nm_utils_is_valid_iface_name (ifname, NULL));
property = NM_ASSERT_VALID_PATH_COMPONENT (property);
len = g_snprintf (path,
sizeof (path),
len = g_snprintf (buf,
NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE,
"%s%s/%s",
ipv6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR,
addr_family == AF_INET6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR,
ifname,
property);
g_assert (len < sizeof (path) - 1);
return path;
g_assert (len < NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE - 1);
return buf;
}
/**
* nm_utils_ip6_property_path:
* @ifname: an interface name
* @property: a property name
*
* Returns the path to IPv6 property @property on @ifname. Note that
* this uses a static buffer.
*/
const char *
nm_utils_ip6_property_path (const char *ifname, const char *property)
gboolean
nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, const char *ifname, const char *property)
{
return _get_property_path (ifname, property, TRUE);
}
g_return_val_if_fail (path, FALSE);
NM_ASSERT_VALID_PATH_COMPONENT (property);
g_assert (!ifname || nm_utils_is_valid_iface_name (ifname, NULL));
/**
* nm_utils_ip4_property_path:
* @ifname: an interface name
* @property: a property name
*
* Returns the path to IPv4 property @property on @ifname. Note that
* this uses a static buffer.
*/
const char *
nm_utils_ip4_property_path (const char *ifname, const char *property)
{
return _get_property_path (ifname, property, FALSE);
if (addr_family == AF_INET) {
if (!g_str_has_prefix (path, IPV4_PROPERTY_DIR))
return FALSE;
path += NM_STRLEN (IPV4_PROPERTY_DIR);
} else if (addr_family == AF_INET6) {
if (!g_str_has_prefix (path, IPV6_PROPERTY_DIR))
return FALSE;
path += NM_STRLEN (IPV6_PROPERTY_DIR);
} else
g_return_val_if_reached (FALSE);
if (ifname) {
if (!g_str_has_prefix (path, ifname))
return FALSE;
path += strlen (ifname);
if (path[0] != '/')
return FALSE;
path++;
} else {
const char *slash;
char buf[IFNAMSIZ];
gsize l;
slash = strchr (path, '/');
if (!slash)
return FALSE;
l = slash - path;
if (l >= IFNAMSIZ)
return FALSE;
memcpy (buf, path, l);
buf[l] = '\0';
if (!nm_utils_is_valid_iface_name (buf, NULL))
return FALSE;
path = slash + 1;
}
if (!nm_streq (path, property))
return FALSE;
return TRUE;
}
gboolean

View File

@@ -248,8 +248,12 @@ gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timest
gboolean nm_utils_is_valid_path_component (const char *name);
const char *NM_ASSERT_VALID_PATH_COMPONENT (const char *name);
const char *nm_utils_ip6_property_path (const char *ifname, const char *property);
const char *nm_utils_ip4_property_path (const char *ifname, const char *property);
#define NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE 100
const char *nm_utils_sysctl_ip_conf_path (int addr_family, char *buf, const char *ifname, const char *property);
gboolean nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, const char *ifname, const char *property);
gboolean nm_utils_is_specific_hostname (const char *name);

View File

@@ -222,9 +222,10 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
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_ip6_property_path (global_opt.ifname, "mtu")), val);
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);
@@ -344,6 +345,7 @@ main (int argc, char *argv[])
gconstpointer tmp;
gs_free NMUtilsIPv6IfaceId *iid = NULL;
guint sd_id;
char sysctl_path_buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
nm_g_type_init ();
@@ -448,7 +450,7 @@ main (int argc, char *argv[])
}
if (global_opt.dhcp4_address) {
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries")), "1");
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),
@@ -497,10 +499,10 @@ main (int argc, char *argv[])
if (iid)
nm_ndisc_set_iid (ndisc, *iid);
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra")), "1");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref")), "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")), "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,

View File

@@ -585,7 +585,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t
return NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
static NMPlatformError
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
@@ -593,13 +593,13 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
if (!device) {
_LOGE ("failure changing link: netlink error (No such device)");
return FALSE;
return NM_PLATFORM_ERROR_EXISTS;
}
obj_tmp = nmp_object_clone (device->obj, FALSE);
obj_tmp->link.mtu = mtu;
link_set_obj (platform, device, obj_tmp);
return TRUE;
return NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean

View File

@@ -206,6 +206,21 @@ typedef enum {
INFINIBAND_ACTION_DELETE_CHILD,
} InfinibandAction;
typedef enum {
CHANGE_LINK_TYPE_UNSPEC,
CHANGE_LINK_TYPE_SET_MTU,
CHANGE_LINK_TYPE_SET_ADDRESS,
} ChangeLinkType;
typedef struct {
union {
struct {
gconstpointer address;
gsize length;
} set_address;
};
} ChangeLinkData;
enum {
DELAYED_ACTION_IDX_REFRESH_ALL_LINKS,
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES,
@@ -2934,7 +2949,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
nm_auto_pop_netns NMPNetns *netns = NULL;
int fd, tries;
gssize nwrote;
gsize len;
gssize len;
char *actual;
gs_free char *actual_free = NULL;
int errsv;
@@ -2989,6 +3004,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
* about to write.
*/
len = strlen (value) + 1;
nm_assert (len > 0);
if (len > 512)
actual = actual_free = g_malloc (len + 1);
else
@@ -3010,9 +3026,20 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
break;
}
}
if (nwrote == -1 && errsv != EEXIST) {
_LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s",
path, value, errsv, strerror (errsv));
if (nwrote == -1) {
NMLogLevel level = LOGL_ERR;
if (errsv == EEXIST) {
level = LOGL_DEBUG;
} else if ( errsv == EINVAL
&& nm_utils_sysctl_ip_conf_is_path (AF_INET6, path, NULL, "mtu")) {
/* setting the MTU can fail under regular conditions. Suppress
* logging a warning. */
level = LOGL_DEBUG;
}
_NMLOG (level, "sysctl: failed to set '%s' to '%s': (%d) %s",
path, value, errsv, strerror (errsv));
} else if (nwrote < len - 1) {
_LOGE ("sysctl: failed to set '%s' to '%s' after three attempts",
path, value);
@@ -4410,25 +4437,38 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
return success;
}
static WaitForNlResponseResult
do_change_link_request (NMPlatform *platform,
int ifindex,
struct nl_msg *nlmsg)
static NMPlatformError
do_change_link (NMPlatform *platform,
ChangeLinkType change_link_type,
int ifindex,
struct nl_msg *nlmsg,
const ChangeLinkData *data)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
char s_buf[256];
NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
NMLogLevel log_level = LOGL_DEBUG;
const char *log_result = "failure";
const char *log_detail = "";
gs_free char *log_detail_free = NULL;
const NMPObject *obj_cache;
if (!nm_platform_netns_push (platform, &netns))
return WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
if (!nm_platform_netns_push (platform, &netns)) {
log_level = LOGL_ERR;
log_detail = ", failure to change network namespace";
goto out;
}
retry:
nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
ifindex,
nl_geterror (nle), -nle);
return WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
log_level = LOGL_ERR;
log_detail_free = g_strdup_printf (", failure sending netlink request: %s (%d)",
nl_geterror (nle), -nle);
log_detail = log_detail_free;
goto out;
}
/* always refetch the link after changing it. There seems to be issues
@@ -4444,18 +4484,6 @@ retry:
nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK;
goto retry;
}
return seq_result;
}
static NMPlatformError
do_change_link_result (NMPlatform *platform,
int ifindex,
WaitForNlResponseResult seq_result)
{
char s_buf[256];
NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
NMLogLevel log_level = LOGL_DEBUG;
const char *log_result = "failure", *log_detail = "";
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
log_result = "success";
@@ -4464,6 +4492,20 @@ do_change_link_result (NMPlatform *platform,
} else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) {
log_detail = ", firmware not found";
result = NM_PLATFORM_ERROR_NO_FIRMWARE;
} else if ( NM_IN_SET (-((int) seq_result), ERANGE)
&& change_link_type == CHANGE_LINK_TYPE_SET_MTU) {
log_detail = ", setting MTU to requested size is not possible";
result = NM_PLATFORM_ERROR_CANT_SET_MTU;
} else if ( NM_IN_SET (-((int) seq_result), ENFILE)
&& change_link_type == CHANGE_LINK_TYPE_SET_ADDRESS
&& (obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex))
&& obj_cache->link.addr.len == data->set_address.length
&& memcmp (obj_cache->link.addr.data, data->set_address.address, data->set_address.length) == 0) {
/* workaround ENFILE which may be wrongly returned (bgo #770456).
* If the MAC address is as expected, assume success? */
log_result = "success";
log_detail = " (assume success changing address)";
result = NM_PLATFORM_ERROR_SUCCESS;
} else if (NM_IN_SET (-((int) seq_result), ENODEV)) {
log_level = LOGL_DEBUG;
result = NM_PLATFORM_ERROR_NOT_FOUND;
@@ -4471,27 +4513,17 @@ do_change_link_result (NMPlatform *platform,
log_level = LOGL_WARN;
result = NM_PLATFORM_ERROR_UNSPECIFIED;
}
out:
_NMLOG (log_level,
"do-change-link[%d]: %s changing link: %s%s",
ifindex,
log_result,
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
log_detail);
return result;
}
static NMPlatformError
do_change_link (NMPlatform *platform,
int ifindex,
struct nl_msg *nlmsg)
{
WaitForNlResponseResult seq_result;
seq_result = do_change_link_request (platform, ifindex, nlmsg);
return do_change_link_result (platform, ifindex, seq_result);
}
static gboolean
link_add (NMPlatform *platform,
const char *name,
@@ -4583,7 +4615,7 @@ link_set_netns (NMPlatform *platform,
return FALSE;
NLA_PUT (nlmsg, IFLA_NET_NS_FD, 4, &netns_fd);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
nla_put_failure:
g_return_val_if_reached (FALSE);
@@ -4613,7 +4645,7 @@ link_change_flags (NMPlatform *platform,
flags_set);
if (!nlmsg)
return NM_PLATFORM_ERROR_UNSPECIFIED;
return do_change_link (platform, ifindex, nlmsg);
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL);
}
static gboolean
@@ -4682,7 +4714,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
|| !_nl_msg_new_link_set_afspec (nlmsg, mode, NULL))
g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
return do_change_link (platform, ifindex, nlmsg);
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL);
}
static gboolean
@@ -4697,7 +4729,7 @@ link_set_token (NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid)
if (!nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, -1, &iid))
g_return_val_if_reached (FALSE);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@@ -4762,8 +4794,12 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
gs_free char *mac = NULL;
WaitForNlResponseResult seq_result;
char s_buf[256];
const ChangeLinkData d = {
.set_address = {
.address = address,
.length = length,
},
};
if (!address || !length)
g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
@@ -4783,30 +4819,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
NLA_PUT (nlmsg, IFLA_ADDRESS, length, address);
seq_result = do_change_link_request (platform, ifindex, nlmsg);
if (NM_IN_SET (-((int) seq_result), ENFILE)) {
const NMPObject *obj_cache;
/* workaround ENFILE which may be wrongly returned (bgo #770456).
* If the MAC address is as expected, assume success? */
obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
if ( obj_cache
&& obj_cache->link.addr.len == length
&& memcmp (obj_cache->link.addr.data, address, length) == 0) {
_NMLOG (LOGL_DEBUG,
"do-change-link[%d]: %s changing link: %s%s",
ifindex,
"success",
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
" (assume success changing address)");
return NM_PLATFORM_ERROR_SUCCESS;
}
}
return do_change_link_result (platform, ifindex, seq_result);
return do_change_link (platform, CHANGE_LINK_TYPE_SET_ADDRESS, ifindex, nlmsg, &d);
nla_put_failure:
g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED);
}
@@ -4829,7 +4842,7 @@ link_set_name (NMPlatform *platform, int ifindex, const char *name)
NLA_PUT (nlmsg, IFLA_IFNAME, strlen (name) + 1, name);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
nla_put_failure:
g_return_val_if_reached (FALSE);
}
@@ -4848,7 +4861,7 @@ link_get_permanent_address (NMPlatform *platform,
return nmp_utils_ethtool_get_permanent_address (ifindex, buf, length);
}
static gboolean
static NMPlatformError
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
@@ -4866,7 +4879,7 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
NLA_PUT_U32 (nlmsg, IFLA_MTU, mtu);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_SET_MTU, ifindex, nlmsg, NULL);
nla_put_failure:
g_return_val_if_reached (FALSE);
}
@@ -5574,7 +5587,7 @@ link_vlan_change (NMPlatform *platform,
new_n_egress_map))
g_return_val_if_reached (FALSE);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static int
@@ -5654,7 +5667,7 @@ link_enslave (NMPlatform *platform, int master, int slave)
NLA_PUT_U32 (nlmsg, IFLA_MASTER, master);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
nla_put_failure:
g_return_val_if_reached (FALSE);
}

View File

@@ -240,6 +240,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_nm_platform_error_to_string, NMPlatformError
NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_ERROR_NO_FIRMWARE, "no-firmware"),
NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_ERROR_OPNOTSUPP, "not-supported"),
NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_ERROR_NETLINK, "netlink"),
NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_ERROR_CANT_SET_MTU, "cant-set-mtu"),
NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_PLATFORM_ERROR_MININT),
);
@@ -413,6 +414,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface,
{
const char *path;
gint64 cur;
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
_CHECK_SELF (self, klass, FALSE);
@@ -424,7 +426,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface,
if (value < 10)
return FALSE;
path = nm_utils_ip6_property_path (iface, "hop_limit");
path = nm_utils_sysctl_ip_conf_path (AF_INET6, buf, iface, "hop_limit");
cur = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), 10, 1, G_MAXINT32, -1);
/* only allow increasing the hop-limit to avoid DOS by an attacker
@@ -1498,7 +1500,7 @@ nm_platform_link_set_noarp (NMPlatform *self, int ifindex)
*
* Set interface MTU.
*/
gboolean
NMPlatformError
nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu)
{
_CHECK_SELF (self, klass, FALSE);

View File

@@ -166,6 +166,7 @@ typedef enum { /*< skip >*/
NM_PLATFORM_ERROR_NO_FIRMWARE,
NM_PLATFORM_ERROR_OPNOTSUPP,
NM_PLATFORM_ERROR_NETLINK,
NM_PLATFORM_ERROR_CANT_SET_MTU,
} NMPlatformError;
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
@@ -718,7 +719,7 @@ typedef struct {
guint8 *buf,
size_t *length);
NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
NMPlatformError (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name);
gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs);
@@ -1060,7 +1061,7 @@ gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtils
gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length);
NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length);
gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
NMPlatformError nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name);
gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs);

View File

@@ -76,7 +76,7 @@ test_bogus(void)
g_assert (!addrlen);
g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU));
g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU) != NM_PLATFORM_ERROR_SUCCESS);
g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX));
@@ -603,7 +603,7 @@ test_internal (void)
accept_signal (link_changed);
/* Set MTU */
g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, MTU));
g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, MTU) == NM_PLATFORM_ERROR_SUCCESS);
g_assert_cmpint (nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex), ==, MTU);
accept_signal (link_changed);

View File

@@ -272,6 +272,32 @@ test_nm_utils_log_connection_diff (void)
/*****************************************************************************/
static void
do_test_sysctl_ip_conf (int addr_family,
const char *iface,
const char *property)
{
char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
const char *pp;
pp = nm_utils_sysctl_ip_conf_path (addr_family, path, iface, property);
g_assert (pp == path);
g_assert (path[0] == '/');
g_assert (nm_utils_sysctl_ip_conf_is_path (addr_family, path, iface, property));
g_assert (nm_utils_sysctl_ip_conf_is_path (addr_family, path, NULL, property));
}
static void
test_nm_utils_sysctl_ip_conf_path (void)
{
do_test_sysctl_ip_conf (AF_INET6, "a", "mtu");
do_test_sysctl_ip_conf (AF_INET6, "eth0", "mtu");
do_test_sysctl_ip_conf (AF_INET6, "e23456789012345", "mtu");
}
/*****************************************************************************/
static NMConnection *
_match_connection_new (void)
{
@@ -1716,6 +1742,8 @@ main (int argc, char **argv)
g_test_add_func ("/general/nm_utils_ip6_address_same_prefix", test_nm_utils_ip6_address_same_prefix);
g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff);
g_test_add_func ("/general/nm_utils_sysctl_ip_conf_path", test_nm_utils_sysctl_ip_conf_path);
g_test_add_func ("/general/exp10", test_nm_utils_exp10);
g_test_add_func ("/general/connection-match/basic", test_connection_match_basic);