platform: merge branch 'lr/udev-unmanaged-fd731014'

https://bugzilla.gnome.org/show_bug.cgi?id=731014

(cherry picked from commit ca9679334c)
This commit is contained in:
Lubomir Rintel 2015-03-23 15:17:07 +01:00 committed by Thomas Haller
commit caa3628976
16 changed files with 167 additions and 59 deletions

View file

@ -87,11 +87,6 @@ libtest_dispatcher_envp_la_LIBADD = \
$(GLIB_LIBS)
if WITH_UDEV_DIR
udevrulesdir = $(UDEV_DIR)/rules.d
udevrules_DATA = 77-nm-olpc-mesh.rules
endif
dbusactivationdir = $(datadir)/dbus-1/system-services
dbusactivation_in_files = org.freedesktop.nm_dispatcher.service.in
dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service)
@ -115,7 +110,6 @@ CLEANFILES = $(nodist_libnmdbus_dispatcher_la_SOURCES) $(dbusactivation_DATA)
EXTRA_DIST = \
$(dbusservice_DATA) \
$(udevrules_DATA) \
$(dbusactivation_in_files) \
nm-dispatcher.xml

View file

@ -494,6 +494,9 @@ make check
%post
/usr/bin/udevadm control --reload-rules || :
/usr/bin/udevadm trigger --subsystem-match=net || :
%systemd_post NetworkManager.service NetworkManager-wait-online.service NetworkManager-dispatcher.service
%preun
@ -507,6 +510,9 @@ fi
%systemd_preun NetworkManager-wait-online.service NetworkManager-dispatcher.service
%postun
/usr/bin/udevadm control --reload-rules || :
/usr/bin/udevadm trigger --subsystem-match=net || :
%systemd_postun

View file

@ -0,0 +1,34 @@
# Do not modify this file, it will get overwriten on updates.
# To override or extend the rules place a file in /etc/udev/rules.d
SUBSYSTEM!="net", GOTO="nm_unmanaged_end"
# Determine ID_NET_DRIVER if there's no ID_NET_DRIVER or DRIVERS (old udev?)
ENV{ID_NET_DRIVER}=="?*", GOTO="nm_unmanaged_driver"
DRIVERS=="?*", GOTO="nm_unmanaged_driver"
PROGRAM="/bin/sh -c '/usr/sbin/ethtool -i $env{INTERFACE} |/bin/sed -n s/^driver:\ //p'", RESULT=="?*", ENV{ID_NET_DRIVER}="%c"
LABEL="nm_unmanaged_driver"
# VirtualBox host networking. Out-of-tree driver that looks like an ordinary
# Ethernet. No parent device (lives in /virtual/), no support for ethtool
# to identify the driver, MAC address defaults to 08:00:27:, but can be
# changed. Interface name will have to do, it's always vboxnet*.
ENV{INTERFACE}=="vboxnet[0-9]*", ENV{NM_UNMANAGED}="1"
# VMWare host networking. Out-of-tree driver that looks like an ordinary
# Ethernet. No parent device (lives in /virtual/), no support for
# ethtool to identify the driver. They have their own MAC prefix that
# can not be changed.
PROGRAM="/bin/cat %S%p/address", RESULT=="00:50:56:*", ENV{INTERFACE}=="vmnet[0-9]*", ENV{NM_UNMANAGED}="1"
# Parallels Workstation host networking. Out-of-tree driver that looks like
# an ordinary Ethernet. No parent device (lives in /virtual/), no support for
# ethtool to identify the driver and the interface name is too generic.
# However, they have their own MAC prefix that can not be changed.
PROGRAM="/bin/cat %S%p/address", RESULT=="00:1c:42:*", ENV{INTERFACE}=="vnic[0-9]*", ENV{NM_UNMANAGED}="1"
# Virtual Ethernet device pair. Often used to communicate with a peer interface
# in another net namespace and managed by libvirt, Docker or the like.
ENV{ID_NET_DRIVER}=="veth", ENV{NM_UNMANAGED}="1"
LABEL="nm_unmanaged_end"

View file

@ -34,6 +34,13 @@ endif
examplesdir = $(docdir)/examples
examples_DATA = server.conf
if WITH_UDEV_DIR
udevrulesdir = $(UDEV_DIR)/rules.d
udevrules_DATA = \
85-nm-unmanaged.rules \
77-nm-olpc-mesh.rules
endif
server.conf: server.conf.in
$(edit) $< >$@
@ -51,6 +58,8 @@ EXTRA_DIST = \
NetworkManager-wait-online-systemd-pre200.service.in \
NetworkManager-dispatcher.service.in \
org.freedesktop.NetworkManager.service.in \
85-nm-unmanaged.rules \
77-nm-olpc-mesh.rules \
server.conf.in
CLEANFILES = \

View file

@ -345,6 +345,33 @@
</variablelist>
</refsect1>
<refsect1>
<title>UDEV PROPERTIES</title>
<para>
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
device manager is used for the network device discovery. The following
property influences how NetworkManager manages the devices:
</para>
<variablelist>
<varlistentry>
<term><varname>NM_UNMANAGED</varname></term>
<listitem><para>
No default connection will be created and automatic activation
will not be attempted when this property of a device is set to a
true value ("1" or "true"). You will still be able to attach a
connection to the device manually or observe externally added
configuration such as addresses or routes.
</para><para>
Create an udev rule that sets this property to prevent NetworkManager
from interfering with virtual Ethernet device interfaces that are
managed by virtualization tools.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>DEBUGGING</title>
<para>
@ -373,6 +400,7 @@
<citerefentry><refentrytitle>nm-settings</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nm-applet</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nm-connection-editor</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View file

@ -102,7 +102,6 @@ get_peer (NMDeviceVeth *self)
static void
nm_device_veth_init (NMDeviceVeth *self)
{
nm_device_set_initial_unmanaged_flag (NM_DEVICE (self), NM_UNMANAGED_DEFAULT, TRUE);
}
static void

View file

@ -1797,7 +1797,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *iface, *driver, *type_desc;
const GSList *unmanaged_specs;
gboolean user_unmanaged, sleeping;
gboolean user_unmanaged, sleeping, platform_unmanaged;
gboolean enabled = FALSE;
RfKillType rtype;
GSList *iter, *remove = NULL;
@ -1877,6 +1877,9 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
if (nm_platform_link_get_unmanaged (nm_device_get_ifindex (device), &platform_unmanaged))
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_DEFAULT, platform_unmanaged);
sleeping = manager_sleeping (self);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);

View file

@ -49,6 +49,11 @@ typedef struct {
int vlan_id;
} NMFakePlatformLink;
typedef struct {
int ifindex;
NMPlatform *platform;
} NMFakePlatformLinkData;
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
@ -174,6 +179,23 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
return !!device;
}
static gboolean
_link_announce (NMFakePlatformLinkData *data)
{
NMFakePlatformLink *device = link_get (data->platform, data->ifindex);
if (device)
g_signal_emit_by_name (data->platform,
NM_PLATFORM_SIGNAL_LINK_CHANGED,
device->link.ifindex,
device,
NM_PLATFORM_SIGNAL_ADDED,
NM_PLATFORM_REASON_INTERNAL);
g_free (data);
return FALSE;
}
static gboolean
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
{
@ -184,8 +206,12 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
g_array_append_val (priv->links, device);
if (device.link.ifindex)
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL);
if (device.link.ifindex) {
NMFakePlatformLinkData *data = g_new (NMFakePlatformLinkData, 1);
data->ifindex = device.link.ifindex;
data->platform = platform;
g_idle_add ((GSourceFunc) _link_announce, data);
}
return TRUE;
}
@ -273,6 +299,12 @@ link_get_type_name (NMPlatform *platform, int ifindex)
return type_to_type_name (link_get_type (platform, ifindex));
}
static gboolean
link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *managed)
{
return FALSE;
}
static void
link_changed (NMPlatform *platform, NMFakePlatformLink *device)
{
@ -1367,6 +1399,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_get_name = link_get_name;
platform_class->link_get_type = link_get_type;
platform_class->link_get_type_name = link_get_type_name;
platform_class->link_get_unmanaged = link_get_unmanaged;
platform_class->link_set_up = link_set_up;
platform_class->link_set_down = link_set_down;

View file

@ -780,41 +780,6 @@ link_type_from_udev (NMPlatform *platform, int ifindex, const char *ifname, int
return_type (NM_LINK_TYPE_UNKNOWN, "unknown");
}
static gboolean
link_is_software (struct rtnl_link *rtnllink)
{
const char *type;
/* FIXME: replace somehow with NMLinkType or nm_platform_is_software(), but
* solve the infinite callstack problems that getting the type of a TUN/TAP
* device causes.
*/
if ( rtnl_link_get_arptype (rtnllink) == ARPHRD_INFINIBAND
&& strchr (rtnl_link_get_name (rtnllink), '.'))
return TRUE;
type = rtnl_link_get_type (rtnllink);
if (type == NULL)
return FALSE;
if (!strcmp (type, "dummy") ||
!strcmp (type, "gre") ||
!strcmp (type, "gretap") ||
!strcmp (type, "macvlan") ||
!strcmp (type, "macvtap") ||
!strcmp (type, "tun") ||
!strcmp (type, "veth") ||
!strcmp (type, "vlan") ||
!strcmp (type, "vxlan") ||
!strcmp (type, "bridge") ||
!strcmp (type, "bond") ||
!strcmp (type, "team"))
return TRUE;
return FALSE;
}
static const char *
ethtool_get_driver (const char *ifname)
{
@ -837,10 +802,6 @@ link_is_announceable (NMPlatform *platform, struct rtnl_link *rtnllink)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
/* Software devices are always visible outside the platform */
if (link_is_software (rtnllink))
return TRUE;
/* Hardware devices must be found by udev so rules get run and tags set */
if (g_hash_table_lookup (priv->udev_devices,
GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink))))
@ -1585,7 +1546,7 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
if (!init_link (platform, &device, rtnl_link))
return;
/* Skip hardware devices not yet discovered by udev. They will be
/* Skip devices not yet discovered by udev. They will be
* announced by udev_device_added(). This doesn't apply to removed
* devices, as those come either from udev_device_removed(),
* event_notification() or link_delete() which block the announcment
@ -1594,7 +1555,7 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
switch (change_type) {
case NM_PLATFORM_SIGNAL_ADDED:
case NM_PLATFORM_SIGNAL_CHANGED:
if (!link_is_software (rtnl_link) && !device.driver)
if (!device.driver)
return;
break;
default:
@ -2439,6 +2400,20 @@ link_get_type_name (NMPlatform *platform, int ifindex)
return type;
}
static gboolean
link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *managed)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
GUdevDevice *udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex));
if (g_udev_device_get_property (udev_device, "NM_UNMANAGED")) {
*managed = g_udev_device_get_property_as_boolean (udev_device, "NM_UNMANAGED");
return TRUE;
}
return FALSE;
}
static guint32
link_get_flags (NMPlatform *platform, int ifindex)
{
@ -4557,7 +4532,12 @@ setup (NMPlatform *platform)
/* And read initial device list */
enumerator = g_udev_enumerator_new (priv->udev_client);
g_udev_enumerator_add_match_subsystem (enumerator, "net");
g_udev_enumerator_add_match_is_initialized (enumerator);
/* Demand that the device is initialized (udev rules ran,
* device has a stable name now) in case udev is running
* (not in a container). */
if (access ("/sys", W_OK) == 0)
g_udev_enumerator_add_match_is_initialized (enumerator);
devices = g_udev_enumerator_execute (enumerator);
for (iter = devices; iter; iter = g_list_next (iter)) {
@ -4625,6 +4605,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_get_name = link_get_name;
platform_class->link_get_type = link_get_type;
platform_class->link_get_type_name = link_get_type_name;
platform_class->link_get_unmanaged = link_get_unmanaged;
platform_class->link_refresh = link_refresh;

View file

@ -684,6 +684,25 @@ nm_platform_link_get_type_name (int ifindex)
return klass->link_get_type_name (platform, ifindex);
}
/**
* nm_platform_link_get_unmanaged:
* @ifindex: Interface index.
* @managed: Management status in case %TRUE is returned
*
* Returns: %TRUE if platform overrides whether the device ought
* to be managed by default. %FALSE with @managed unmodified
* otherwise.
*/
gboolean
nm_platform_link_get_unmanaged (int ifindex, gboolean *managed)
{
reset_error ();
g_return_val_if_fail (klass->link_get_unmanaged, FALSE);
return klass->link_get_unmanaged (platform, ifindex, managed);
}
/**
* nm_platform_link_is_software:
* @ifindex: Interface index.

View file

@ -368,6 +368,7 @@ typedef struct {
const char *(*link_get_name) (NMPlatform *, int ifindex);
NMLinkType (*link_get_type) (NMPlatform *, int ifindex);
const char *(*link_get_type_name) (NMPlatform *, int ifindex);
gboolean (*link_get_unmanaged) (NMPlatform *, int ifindex, gboolean *managed);
gboolean (*link_refresh) (NMPlatform *, int ifindex);
@ -517,6 +518,7 @@ int nm_platform_link_get_ifindex (const char *name);
const char *nm_platform_link_get_name (int ifindex);
NMLinkType nm_platform_link_get_type (int ifindex);
const char *nm_platform_link_get_type_name (int ifindex);
gboolean nm_platform_link_get_unmanaged (int ifindex, gboolean *managed);
gboolean nm_platform_link_is_software (int ifindex);
gboolean nm_platform_link_supports_slaves (int ifindex);

View file

@ -256,7 +256,7 @@ setup_tests (void)
nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
g_assert (!nm_platform_link_exists (DEVICE_NAME));
g_assert (nm_platform_dummy_add (DEVICE_NAME));
accept_signal (link_added);
wait_signal (link_added);
free_signal (link_added);
g_test_add_func ("/address/internal/ip4", test_ip4_address);

View file

@ -36,7 +36,7 @@ test_cleanup_internal (void)
/* Create and set up device */
g_assert (nm_platform_dummy_add (DEVICE_NAME));
accept_signal (link_added);
wait_signal (link_added);
free_signal (link_added);
g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);

View file

@ -115,7 +115,7 @@ software_add (NMLinkType link_type, const char *name)
/* Don't call link_callback for the bridge interface */
parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
if (nm_platform_bridge_add (PARENT_NAME, NULL, 0))
accept_signal (parent_added);
wait_signal (parent_added);
free_signal (parent_added);
{
@ -148,7 +148,7 @@ test_slave (int master, int type, SignalData *master_changed)
g_assert (ifindex > 0);
link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
accept_signal (link_added);
wait_signal (link_added);
/* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
*
@ -263,7 +263,7 @@ test_software (NMLinkType link_type, const char *link_typename)
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
g_assert (software_add (link_type, DEVICE_NAME));
no_error ();
accept_signal (link_added);
wait_signal (link_added);
g_assert (nm_platform_link_exists (DEVICE_NAME));
ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
g_assert (ifindex >= 0);
@ -405,7 +405,7 @@ test_internal (void)
/* Add device */
g_assert (nm_platform_dummy_add (DEVICE_NAME));
no_error ();
accept_signal (link_added);
wait_signal (link_added);
/* Try to add again */
g_assert (!nm_platform_dummy_add (DEVICE_NAME));

View file

@ -321,7 +321,7 @@ setup_tests (void)
nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
g_assert (!nm_platform_link_exists (DEVICE_NAME));
g_assert (nm_platform_dummy_add (DEVICE_NAME));
accept_signal (link_added);
wait_signal (link_added);
free_signal (link_added);
g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));