Commit e2137076 authored by Dan Winship's avatar Dan Winship

settings: add unrecognized-specs, implement in ifcfg-rh

In Fedora, OVS ports are now identified in ifcfg files as
"TYPE=OVSPort", which NM doesn't recognize, and so it would ignore
those ifcfg files. Unfortunately, this meant that if auto-default
wasn't disabled, and there was no other configuration defined for the
device, then NM would create an NMDefaultWiredConnection for it and
screw things up.

So, add an "unrecognized-specs" settings plugin property, which allows
a plugin to indicate to NetworkManager that it knows of some
non-NetworkManager-supported connection defined for a device. This
will suppress default-wired connection creation for that device,
similar to the "no-auto-default" config file option, but determined by
the plugin instead of by manual configuration. Devices listed in
unrecognized-specs may still be managed by NetworkManager, unless they
are also listed in unmanaged-specs.

https://bugzilla.redhat.com/show_bug.cgi?id=1022256
parent 0d3674a5
......@@ -115,6 +115,7 @@ static void impl_settings_save_hostname (NMSettings *self,
#include "nm-settings-glue.h"
static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
static void unrecognized_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
static void connection_provider_init (NMConnectionProvider *cp_class);
......@@ -136,6 +137,7 @@ typedef struct {
gboolean connections_loaded;
GHashTable *connections;
GSList *unmanaged_specs;
GSList *unrecognized_specs;
GSList *get_connections_cache;
} NMSettingsPrivate;
......@@ -201,11 +203,14 @@ load_connections (NMSettings *self)
G_CALLBACK (plugin_connection_added), self);
g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED,
G_CALLBACK (unmanaged_specs_changed), self);
g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED,
G_CALLBACK (unrecognized_specs_changed), self);
}
priv->connections_loaded = TRUE;
unmanaged_specs_changed (NULL, self);
unrecognized_specs_changed (NULL, self);
g_signal_emit (self, signals[CONNECTIONS_LOADED], 0);
g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTIONS_LOADED);
......@@ -356,15 +361,6 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path)
return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path);
}
static void
clear_unmanaged_specs (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
g_slist_free_full (priv->unmanaged_specs, g_free);
priv->unmanaged_specs = NULL;
}
static char*
uscore_to_wincaps (const char *uscore)
{
......@@ -466,46 +462,65 @@ nm_settings_get_hostname (NMSettings *self)
}
static gboolean
find_unmanaged_device (NMSettings *self, const char *needle)
find_spec (GSList *spec_list, const char *spec)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->unmanaged_specs; iter; iter = g_slist_next (iter)) {
if (!strcmp ((const char *) iter->data, needle))
for (iter = spec_list; iter; iter = g_slist_next (iter)) {
if (!strcmp ((const char *) iter->data, spec))
return TRUE;
}
return FALSE;
}
static void
unmanaged_specs_changed (NMSystemConfigInterface *config,
gpointer user_data)
update_specs (NMSettings *self, GSList **specs_ptr,
GSList * (*get_specs_func) (NMSystemConfigInterface *))
{
NMSettings *self = NM_SETTINGS (user_data);
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GSList *iter;
clear_unmanaged_specs (self);
g_slist_free_full (*specs_ptr, g_free);
*specs_ptr = NULL;
/* Ask all the plugins for their unmanaged specs */
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
GSList *specs, *specs_iter;
specs = nm_system_config_interface_get_unmanaged_specs (NM_SYSTEM_CONFIG_INTERFACE (iter->data));
specs = get_specs_func (NM_SYSTEM_CONFIG_INTERFACE (iter->data));
for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) {
if (!find_unmanaged_device (self, (const char *) specs_iter->data)) {
priv->unmanaged_specs = g_slist_prepend (priv->unmanaged_specs, specs_iter->data);
if (!find_spec (*specs_ptr, (const char *) specs_iter->data)) {
*specs_ptr = g_slist_prepend (*specs_ptr, specs_iter->data);
} else
g_free (specs_iter->data);
}
g_slist_free (specs);
}
}
static void
unmanaged_specs_changed (NMSystemConfigInterface *config,
gpointer user_data)
{
NMSettings *self = NM_SETTINGS (user_data);
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
update_specs (self, &priv->unmanaged_specs,
nm_system_config_interface_get_unmanaged_specs);
g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS);
}
static void
unrecognized_specs_changed (NMSystemConfigInterface *config,
gpointer user_data)
{
NMSettings *self = NM_SETTINGS (user_data);
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
update_specs (self, &priv->unrecognized_specs,
nm_system_config_interface_get_unrecognized_specs);
}
static void
hostname_changed (NMSystemConfigInterface *config,
GParamSpec *pspec,
......@@ -1430,6 +1445,10 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
}
}
/* See if there's a known non-NetworkManager configuration for the device */
if (nm_device_spec_match_list (device, priv->unrecognized_specs))
return TRUE;
return FALSE;
}
......@@ -1698,6 +1717,7 @@ nm_settings_new (GError **error)
}
unmanaged_specs_changed (NULL, self);
unrecognized_specs_changed (NULL, self);
nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
return self;
......@@ -1757,7 +1777,8 @@ finalize (GObject *object)
g_hash_table_destroy (priv->connections);
g_slist_free (priv->get_connections_cache);
clear_unmanaged_specs (self);
g_slist_free_full (priv->unmanaged_specs, g_free);
g_slist_free_full (priv->unrecognized_specs, g_free);
g_slist_free_full (priv->plugins, g_object_unref);
......
......@@ -84,6 +84,14 @@ interface_init (gpointer g_iface)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED,
iface_type,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMSystemConfigInterface, unrecognized_specs_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
initialized = TRUE;
}
......@@ -156,6 +164,16 @@ nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config)
return NULL;
}
GSList *
nm_system_config_interface_get_unrecognized_specs (NMSystemConfigInterface *config)
{
g_return_val_if_fail (config != NULL, NULL);
if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unrecognized_specs)
return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unrecognized_specs (config);
return NULL;
}
/**
* nm_system_config_interface_add_connection:
* @config: the #NMSystemConfigInterface
......
......@@ -53,6 +53,7 @@ GObject * nm_system_config_factory (void);
#define NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME "hostname"
#define NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed"
#define NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED "unrecognized-specs-changed"
#define NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED "connection-added"
typedef enum {
......@@ -100,20 +101,23 @@ struct _NMSystemConfigInterface {
* service, and each element must be allocated using g_malloc() or its
* variants (g_strdup, g_strdup_printf, etc).
*
* Each string in the list must follow the format <method>:<data>, where
* the method and data are one of the following:
*
* Method: mac Data: device MAC address formatted with leading zeros and
* lowercase letters, like 00:0a:0b:0c:0d:0e
*
* Method: s390-subchannels Data: string of 2 or 3 s390 subchannels
* separated by commas (,) that identify the
* device, like "0.0.09a0,0.0.09a1,0.0.09a2".
* The string may contain only the following
* characters: [a-fA-F0-9,.]
* Each string in the list must be in one of the formats recognized by
* nm_device_spec_match_list().
*/
GSList * (*get_unmanaged_specs) (NMSystemConfigInterface *config);
/*
* Return a string list of specifications of devices for which at least
* one non-NetworkManager-based configuration is defined. Returned list
* will be freed by the system settings service, and each element must be
* allocated using g_malloc() or its variants (g_strdup, g_strdup_printf,
* etc).
*
* Each string in the list must be in one of the formats recognized by
* nm_device_spec_match_list().
*/
GSList * (*get_unrecognized_specs) (NMSystemConfigInterface *config);
/*
* Initialize the plugin-specific connection and return a new
* NMSettingsConnection subclass that contains the same settings as the
......@@ -134,6 +138,9 @@ struct _NMSystemConfigInterface {
/* Emitted when the list of unmanaged device specifications changes */
void (*unmanaged_specs_changed) (NMSystemConfigInterface *config);
/* Emitted when the list of devices with unrecognized connections changes */
void (*unrecognized_specs_changed) (NMSystemConfigInterface *config);
};
GType nm_system_config_interface_get_type (void);
......@@ -146,6 +153,7 @@ GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *con
void nm_system_config_interface_reload_connections (NMSystemConfigInterface *config);
GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config);
GSList *nm_system_config_interface_get_unrecognized_specs (NMSystemConfigInterface *config);
NMSettingsConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config,
NMConnection *connection,
......
......@@ -61,12 +61,14 @@ typedef struct {
char *route6file;
int route6file_wd;
char *unmanaged;
char *unmanaged_spec;
char *unrecognized_spec;
} NMIfcfgConnectionPrivate;
enum {
PROP_0,
PROP_UNMANAGED,
PROP_UNMANAGED_SPEC,
PROP_UNRECOGNIZED_SPEC,
LAST_PROP
};
......@@ -105,7 +107,8 @@ nm_ifcfg_connection_new (NMConnection *source,
{
GObject *object;
NMConnection *tmp;
char *unmanaged = NULL;
char *unhandled_spec = NULL;
const char *unmanaged_spec = NULL, *unrecognized_spec = NULL;
gboolean update_unsaved = TRUE;
g_assert (source || full_path);
......@@ -117,7 +120,7 @@ nm_ifcfg_connection_new (NMConnection *source,
char *keyfile = NULL, *routefile = NULL, *route6file = NULL;
tmp = connection_from_file (full_path, NULL, NULL, NULL,
&unmanaged,
&unhandled_spec,
&keyfile,
&routefile,
&route6file,
......@@ -133,8 +136,14 @@ nm_ifcfg_connection_new (NMConnection *source,
update_unsaved = FALSE;
}
if (unhandled_spec && g_str_has_prefix (unhandled_spec, "unmanaged:"))
unmanaged_spec = unhandled_spec + strlen ("unmanaged:");
else if (unhandled_spec && g_str_has_prefix (unhandled_spec, "unrecognized:"))
unrecognized_spec = unhandled_spec + strlen ("unrecognized:");
object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
NM_IFCFG_CONNECTION_UNMANAGED, unmanaged,
NM_IFCFG_CONNECTION_UNMANAGED_SPEC, unmanaged_spec,
NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, unrecognized_spec,
NULL);
if (object) {
/* Update our settings with what was read from the file */
......@@ -152,6 +161,7 @@ nm_ifcfg_connection_new (NMConnection *source,
}
g_object_unref (tmp);
g_free (unhandled_spec);
return (NMIfcfgConnection *) object;
}
......@@ -234,7 +244,15 @@ nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self)
{
g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged;
return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged_spec;
}
const char *
nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self)
{
g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unrecognized_spec;
}
static void
......@@ -344,8 +362,11 @@ set_property (GObject *object, guint prop_id,
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
switch (prop_id) {
case PROP_UNMANAGED:
priv->unmanaged = g_value_dup_string (value);
case PROP_UNMANAGED_SPEC:
priv->unmanaged_spec = g_value_dup_string (value);
break;
case PROP_UNRECOGNIZED_SPEC:
priv->unrecognized_spec = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -360,8 +381,11 @@ get_property (GObject *object, guint prop_id,
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
switch (prop_id) {
case PROP_UNMANAGED:
g_value_set_string (value, priv->unmanaged);
case PROP_UNMANAGED_SPEC:
g_value_set_string (value, priv->unmanaged_spec);
break;
case PROP_UNRECOGNIZED_SPEC:
g_value_set_string (value, priv->unrecognized_spec);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -386,12 +410,19 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
/* Properties */
g_object_class_install_property
(object_class, PROP_UNMANAGED,
g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED,
"Unmanaged",
"Unmanaged",
(object_class, PROP_UNMANAGED_SPEC,
g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED_SPEC,
"Unmanaged spec",
"Unmanaged spec",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class, PROP_UNRECOGNIZED_SPEC,
g_param_spec_string (NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC,
"Unrecognized spec",
"Unrecognized spec",
NULL,
G_PARAM_READWRITE));
signals[IFCFG_CHANGED] =
g_signal_new ("ifcfg-changed",
......
......@@ -33,7 +33,8 @@ G_BEGIN_DECLS
#define NM_IS_IFCFG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IFCFG_CONNECTION))
#define NM_IFCFG_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass))
#define NM_IFCFG_CONNECTION_UNMANAGED "unmanaged"
#define NM_IFCFG_CONNECTION_UNMANAGED_SPEC "unmanaged-spec"
#define NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC "unrecognized-spec"
typedef struct {
NMSettingsConnection parent;
......@@ -56,6 +57,7 @@ void nm_ifcfg_connection_set_path (NMIfcfgConnection *self,
const char *ifcfg_path);
const char *nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self);
const char *nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self);
gboolean nm_ifcfg_connection_update (NMIfcfgConnection *self,
GHashTable *new_settings,
......
......@@ -163,6 +163,9 @@ _internal_new_connection (SCPluginIfcfg *self,
device_id = spec;
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' / device '%s' "
"due to NM_CONTROLLED=no.", cid, device_id);
} else if (nm_ifcfg_connection_get_unrecognized_spec (connection)) {
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' "
"of unrecognized type.", cid);
}
/* watch changes of ifcfg hardlinks */
......@@ -178,21 +181,24 @@ static void
remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
gboolean managed = FALSE;
gboolean unmanaged, unrecognized;
g_return_if_fail (self != NULL);
g_return_if_fail (connection != NULL);
managed = !nm_ifcfg_connection_get_unmanaged_spec (connection);
unmanaged = !!nm_ifcfg_connection_get_unmanaged_spec (connection);
unrecognized = !!nm_ifcfg_connection_get_unrecognized_spec (connection);
g_object_ref (connection);
g_hash_table_remove (priv->connections, nm_connection_get_uuid (NM_CONNECTION (connection)));
nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
g_object_unref (connection);
/* Emit unmanaged changes _after_ removing the connection */
if (managed == FALSE)
/* Emit changes _after_ removing the connection */
if (unmanaged)
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
if (unrecognized)
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
}
static NMIfcfgConnection *
......@@ -238,6 +244,8 @@ connection_new_or_changed (SCPluginIfcfg *self,
GError *error = NULL;
gboolean ignore_error = FALSE;
const char *new_unmanaged = NULL, *old_unmanaged = NULL;
const char *new_unrecognized = NULL, *old_unrecognized = NULL;
gboolean unmanaged_changed, unrecognized_changed;
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
......@@ -261,12 +269,12 @@ connection_new_or_changed (SCPluginIfcfg *self,
/* New connection */
new = _internal_new_connection (self, path, NULL, NULL);
if (new) {
if (nm_ifcfg_connection_get_unmanaged_spec (new)) {
if (nm_ifcfg_connection_get_unmanaged_spec (new))
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
} else {
/* Only managed connections are announced to the settings service */
else if (nm_ifcfg_connection_get_unrecognized_spec (new))
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
else
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new);
}
}
return;
}
......@@ -289,25 +297,30 @@ connection_new_or_changed (SCPluginIfcfg *self,
old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (existing));
new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new));
/* When interface is unmanaged or the connections and unmanaged specs are the same
* there's nothing to do */
if ( (g_strcmp0 (old_unmanaged, new_unmanaged) == 0 && new_unmanaged != NULL)
|| ( nm_connection_compare (NM_CONNECTION (existing),
NM_CONNECTION (new),
NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
&& g_strcmp0 (old_unmanaged, new_unmanaged) == 0)) {
unmanaged_changed = g_strcmp0 (old_unmanaged, new_unmanaged);
old_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (NM_IFCFG_CONNECTION (existing));
new_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (NM_IFCFG_CONNECTION (new));
unrecognized_changed = g_strcmp0 (old_unrecognized, new_unrecognized);
if ( !unmanaged_changed
&& !unrecognized_changed
&& nm_connection_compare (NM_CONNECTION (existing),
NM_CONNECTION (new),
NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
g_object_unref (new);
return;
}
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path);
g_object_set (existing, NM_IFCFG_CONNECTION_UNMANAGED, new_unmanaged, NULL);
g_object_set (existing,
NM_IFCFG_CONNECTION_UNMANAGED_SPEC, new_unmanaged,
NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized,
NULL);
if (new_unmanaged) {
if (!old_unmanaged) {
if (new_unmanaged || new_unrecognized) {
if (!old_unmanaged && !old_unrecognized) {
g_object_ref (existing);
/* Unexport the connection by telling the settings service it's
* been removed.
......@@ -325,12 +338,16 @@ connection_new_or_changed (SCPluginIfcfg *self,
existing);
}
} else {
if (old_unmanaged) { /* now managed */
const char *cid = nm_connection_get_id (NM_CONNECTION (new));
const char *cid = nm_connection_get_id (NM_CONNECTION (new));
if (old_unmanaged /* && !new_unmanaged */) {
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Managing connection '%s' and its "
"device because NM_CONTROLLED was true.", cid);
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing);
} else if (old_unrecognized /* && !new_unrecognized */) {
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Managing connection '%s' "
"because it is now a recognized type.", cid);
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing);
}
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (existing),
......@@ -343,8 +360,10 @@ connection_new_or_changed (SCPluginIfcfg *self,
}
g_object_unref (new);
if (g_strcmp0 (old_unmanaged, new_unmanaged))
if (unmanaged_changed)
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
if (unrecognized_changed)
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED);
}
static void
......@@ -482,7 +501,8 @@ get_connections (NMSystemConfigInterface *config)
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) {
if (!nm_ifcfg_connection_get_unmanaged_spec (connection))
if ( !nm_ifcfg_connection_get_unmanaged_spec (connection)
&& !nm_ifcfg_connection_get_unrecognized_spec (connection))
list = g_slist_prepend (list, connection);
}
......@@ -498,18 +518,19 @@ reload_connections (NMSystemConfigInterface *config)
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
get_unhandled_specs (NMSystemConfigInterface *config,
const char *property)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
GSList *list = NULL, *list_iter;
GHashTableIter iter;
NMIfcfgConnection *connection;
const char *spec;
gpointer connection;
char *spec;
gboolean found;
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) {
spec = nm_ifcfg_connection_get_unmanaged_spec (connection);
while (g_hash_table_iter_next (&iter, NULL, &connection)) {
g_object_get (connection, property, &spec, NULL);
if (spec) {
/* Ignore duplicates */
for (list_iter = list, found = FALSE; list_iter; list_iter = g_slist_next (list_iter)) {
......@@ -518,13 +539,27 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
break;
}
}
if (!found)
list = g_slist_prepend (list, g_strdup (spec));
if (found)
g_free (spec);
else
list = g_slist_prepend (list, spec);
}
}
return list;
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
return get_unhandled_specs (config, NM_IFCFG_CONNECTION_UNMANAGED_SPEC);
}
static GSList *
get_unrecognized_specs (NMSystemConfigInterface *config)
{
return get_unhandled_specs (config, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC);
}
static NMSettingsConnection *
add_connection (NMSystemConfigInterface *config,
NMConnection *connection,
......@@ -678,7 +713,9 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
}
connection = find_by_path (plugin, in_ifcfg);
if (!connection || nm_ifcfg_connection_get_unmanaged_spec (connection)) {
if ( !connection
|| nm_ifcfg_connection_get_unmanaged_spec (connection)
|| nm_ifcfg_connection_get_unrecognized_spec (connection)) {
g_set_error (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
......@@ -930,6 +967,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c
system_config_interface_class->add_connection = add_connection;
system_config_interface_class->reload_connections = reload_connections;
system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs;
system_config_interface_class->get_unrecognized_specs = get_unrecognized_specs;
system_config_interface_class->init = init;
}
......
......@@ -4739,34 +4739,53 @@ vlan_connection_from_ifcfg (const char *file,
return connection;
}
static char *
get_unmanaged_spec (shvarFile *ifcfg)
static NMConnection *
create_unhandled_connection (const char *filename, shvarFile *ifcfg,
const char *type, char **out_spec)
{
char *value, *unmanaged;
NMConnection *connection;
NMSetting *s_con;
char *value;
g_assert (out_spec != NULL);
connection = nm_connection_new ();
/* Get NAME, UUID, etc. We need to set a connection type (generic) and add
* an empty type-specific setting as well, to make sure it passes
* nm_connection_verify() later.
*/
s_con = make_connection_setting (filename, ifcfg, NM_SETTING_GENERIC_SETTING_NAME,
NULL, NULL);
nm_connection_add_setting (connection, s_con);
nm_connection_add_setting (connection, nm_setting_generic_new ());
/* Get a spec */
value = svGetValue (ifcfg, "HWADDR", FALSE);
if (value) {
char *lower = g_ascii_strdown (value, -1);
unmanaged = g_strdup_printf ("mac:%s", lower);
*out_spec = g_strdup_printf ("%s:mac:%s", type, lower);
g_free (lower);
g_free (value);
return unmanaged;
return connection;
}
value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
if (value) {
unmanaged = g_strdup_printf ("s390-subchannels:%s", value);
*out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value);
g_free (value);
return unmanaged;
return connection;
}
value = svGetValue (ifcfg, "DEVICE", FALSE);
if (value) {
unmanaged = g_strdup_printf ("interface-name:%s", value);
*out_spec = g_strdup_printf ("%s:interface-name:%s", type, value);
g_free (value);
return unmanaged;
return connection;
}
g_object_unref (connection);
return NULL;
}
......@@ -4832,7 +4851,7 @@ connection_from_file (const char *filename,
const char *network_file, /* for unit tests only */
const char *test_type, /* for unit tests only */
const char *iscsiadm_path, /* for unit tests only */
char **out_unmanaged,
char **out_unhandled,
char **out_keyfile,
char **out_routefile,
char **out_route6file,
......@@ -4846,8 +4865,8 @@ connection_from_file (const char *filename,
const char *ifcfg_name = NULL;
g_return_val_if_fail (filename != NULL, NULL);
if (out_unmanaged)
g_return_val_if_fail (*out_unmanaged == NULL, NULL);
if (out_unhandled)
g_return_val_if_fail (*out_unhandled == NULL, NULL);
if (out_keyfile)
g_return_val_if_fail (*out_keyfile == NULL, NULL);
if (out_routefile)
......@@ -4877,22 +4896,11 @@ connection_from_file (const char *filename,
}
if (!svTrueValue (parsed, "NM_CONTROLLED", TRUE)) {
NMSetting *s_con;
g_assert (out_unmanaged != NULL);
g_assert (out_unhandled != NULL);
connection = nm_connection_new ();
/* Get NAME, UUID, etc. We need to set a connection type (generic) and add
* an empty type-specific setting as well, to make sure it passes
* nm_connection_verify() later.
*/
s_con = make_connection_setting (filename, parsed, NM_SETTING_GENERIC_SETTING_NAME,
NULL, NULL);
nm_connection_add_setting (connection, s_con);
nm_connection_add_setting (connection, nm_setting_generic_new ());
*out_unmanaged = get_unmanaged_spec (parsed);
connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
if (!connection)
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
goto done;
}
......@@ -4977,7 +4985,12 @@ connection_from_file (const char *filename,
else if (!strcasecmp (type, TYPE_BRIDGE))
connection = bridge_connection_from_ifcfg (filename, parsed, error);
else {
g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Unknown connection type '%s'", type);
g_assert (out_unhandled != NULL);
connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
if (