summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-03-17 16:18:48 +0100
committerThomas Haller <thaller@redhat.com>2017-03-17 17:40:00 +0100
commitb869d9cc0dda4fe5300f5ec5b5a090199ecd4e3e (patch)
tree654c693a00aaf40f3293c8b9f452c8622f777138
parent4c6edb22b70249c302209dc4af29c5caa88a764d (diff)
device: add spec "driver:" to match devices
Changing the MAC address of devices is known to fail with certain drivers. Add a device-spec to allow disabling it for for such devices. Related: https://bugzilla.gnome.org/show_bug.cgi?id=777523
-rw-r--r--Makefile.examples1
-rw-r--r--examples/nm-conf.d/31-mac-addr-change.conf11
-rw-r--r--man/NetworkManager.conf.xml7
-rw-r--r--src/devices/nm-device.c2
-rw-r--r--src/nm-core-utils.c39
-rw-r--r--src/nm-core-utils.h2
-rw-r--r--src/tests/test-general.c33
7 files changed, 93 insertions, 2 deletions
diff --git a/Makefile.examples b/Makefile.examples
index 61c2b1df6e..f464b061d6 100644
--- a/Makefile.examples
+++ b/Makefile.examples
@@ -138,6 +138,7 @@ EXTRA_DIST += \
examples/lua/lgi/deactivate-all.lua \
\
examples/nm-conf.d/30-anon.conf \
+ examples/nm-conf.d/31-mac-addr-change.conf \
\
examples/python/dbus/nm-state.py \
examples/python/dbus/add-connection.py \
diff --git a/examples/nm-conf.d/31-mac-addr-change.conf b/examples/nm-conf.d/31-mac-addr-change.conf
new file mode 100644
index 0000000000..1ae2e0dc12
--- /dev/null
+++ b/examples/nm-conf.d/31-mac-addr-change.conf
@@ -0,0 +1,11 @@
+# Certain drivers are known not to support changing the MAC address.
+# Disable touching the MAC address on such devices.
+#
+# See man NetworkManager.conf
+#
+# https://bugzilla.gnome.org/show_bug.cgi?id=777523
+[device-mac-addr-change-wifi]
+match-device=driver:rtl8723bs,driver:rtl8189es,driver:r8188eu,driver:eagle_sdio
+wifi.scan-rand-mac-address=no
+wifi.cloned-mac-address=preserve
+ethernet.cloned-mac-address=preserve
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 7ca496bfb0..13282f488b 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -1173,6 +1173,13 @@ enable=nm-version-min:1.3,nm-version-min:1.2.6,nm-version-min:1.0.16
Globbing is not supported.</para></listitem>
</varlistentry>
<varlistentry>
+ <term>driver:DRIVER</term>
+ <listitem><para>Match the device driver as reported by "<literal>nmcli -f GENERAL.DRIVER,GENERAL.DRIVER-VERSION device show</literal>".
+ "<literal>DRIVER</literal>" must match the driver name exactly and does not support globbing.
+ Optionally, a driver version may be specified separated by '/'. Globbing is supported for the version.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term>except:SPEC</term>
<listitem><para>Negative match of a device. <literal>SPEC</literal> must be explicitly qualified with
a prefix such as <literal>interface-name:</literal>. A negative match has higher priority then the positive
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 0632463605..de9bf78bc7 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -13193,6 +13193,8 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs)
m = nm_match_spec_device (specs,
nm_device_get_iface (self),
nm_device_get_type_description (self),
+ nm_device_get_driver (self),
+ nm_device_get_driver_version (self),
nm_device_get_permanent_hw_address (self),
klass->get_s390_subchannels ? klass->get_s390_subchannels (self) : NULL);
return m == NM_MATCH_SPEC_MATCH;
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index adef77e296..25ca18853e 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -1182,6 +1182,7 @@ nm_utils_read_link_absolute (const char *link_file, GError **error)
#define MAC_TAG "mac:"
#define INTERFACE_NAME_TAG "interface-name:"
#define DEVICE_TYPE_TAG "type:"
+#define DRIVER_TAG "driver:"
#define SUBCHAN_TAG "s390-subchannels:"
#define EXCEPT_TAG "except:"
#define MATCH_TAG_CONFIG_NM_VERSION "nm-version:"
@@ -1192,6 +1193,8 @@ nm_utils_read_link_absolute (const char *link_file, GError **error)
typedef struct {
const char *interface_name;
const char *device_type;
+ const char *driver;
+ const char *driver_version;
struct {
const char *value;
gboolean is_parsed;
@@ -1374,6 +1377,38 @@ match_device_eval (const char *spec_str,
return FALSE;
}
+ if (_MATCH_CHECK (spec_str, DRIVER_TAG)) {
+ const char *t;
+
+ if (!match_data->driver)
+ return FALSE;
+
+ /* support:
+ * 1) "${DRIVER}"
+ * In this case, DRIVER may not contain a '/' character.
+ * It matches any driver version.
+ * 2) "${DRIVER}/${DRIVER_VERSION}"
+ * In this case, DRIVER may contains '/' but DRIVER_VERSION
+ * may not. A '/' in DRIVER_VERSION may be replaced by '?'.
+ *
+ * It follows, that "${DRIVER}/""*" is like 1), but allows
+ * '/' inside DRIVER.
+ *
+ * The fields match to what `nmcli -f GENERAL.DRIVER,GENERAL.DRIVER-VERSION device show`
+ * gives. However, DRIVER matches literally, while DRIVER_VERSION is a glob
+ * supporting ? and *.
+ */
+
+ t = strrchr (spec_str, '/');
+
+ if (!t)
+ return nm_streq (spec_str, match_data->driver);
+
+ return (strncmp (spec_str, match_data->driver, t - spec_str) == 0)
+ && g_pattern_match_simple (&t[1],
+ match_data->driver_version ?: "");
+ }
+
if (_MATCH_CHECK (spec_str, SUBCHAN_TAG))
return match_data_s390_subchannels_eval (spec_str, match_data);
@@ -1392,6 +1427,8 @@ NMMatchSpecMatchType
nm_match_spec_device (const GSList *specs,
const char *interface_name,
const char *device_type,
+ const char *driver,
+ const char *driver_version,
const char *hwaddr,
const char *s390_subchannels)
{
@@ -1402,6 +1439,8 @@ nm_match_spec_device (const GSList *specs,
MatchDeviceData match_data = {
.interface_name = interface_name,
.device_type = nm_str_not_empty (device_type),
+ .driver = nm_str_not_empty (driver),
+ .driver_version = nm_str_not_empty (driver_version),
.hwaddr = {
.value = hwaddr,
},
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index 779ba90ab9..f9fa88a29b 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -142,6 +142,8 @@ typedef enum {
NMMatchSpecMatchType nm_match_spec_device (const GSList *specs,
const char *interface_name,
+ const char *driver,
+ const char *driver_version,
const char *device_type,
const char *hwaddr,
const char *s390_subchannels);
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index cecce83f2c..498615822e 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -986,13 +986,25 @@ test_connection_sort_autoconnect_priority (void)
/*****************************************************************************/
#define MATCH_S390 "S390:"
+#define MATCH_DRIVER "DRIVER:"
static NMMatchSpecMatchType
_test_match_spec_device (const GSList *specs, const char *match_str)
{
if (match_str && g_str_has_prefix (match_str, MATCH_S390))
- return nm_match_spec_device (specs, NULL, NULL, NULL, &match_str[NM_STRLEN (MATCH_S390)]);
- return nm_match_spec_device (specs, match_str, NULL, NULL, NULL);
+ return nm_match_spec_device (specs, NULL, NULL, NULL, NULL, NULL, &match_str[NM_STRLEN (MATCH_S390)]);
+ if (match_str && g_str_has_prefix (match_str, MATCH_DRIVER)) {
+ gs_free char *s = g_strdup (&match_str[NM_STRLEN (MATCH_DRIVER)]);
+ char *t;
+
+ t = strchr (s, '|');
+ if (t) {
+ t[0] = '\0';
+ t++;
+ }
+ return nm_match_spec_device (specs, NULL, NULL, s, t, NULL, NULL);
+ }
+ return nm_match_spec_device (specs, match_str, NULL, NULL, NULL, NULL, NULL);
}
static void
@@ -1142,6 +1154,23 @@ test_match_spec_device (void)
NULL,
S (NULL),
S (MATCH_S390"0.0.1000", MATCH_S390"0.0.1000,deadbeef", MATCH_S390"0.0.1000,0.0.1001", MATCH_S390"0.0.1000,0.0.1002"));
+
+ _do_test_match_spec_device ("driver:DRV",
+ S (MATCH_DRIVER"DRV", MATCH_DRIVER"DRV|1.6"),
+ S (MATCH_DRIVER"DR", MATCH_DRIVER"DR*"),
+ NULL);
+ _do_test_match_spec_device ("driver:DRV//",
+ S (MATCH_DRIVER"DRV/"),
+ S (MATCH_DRIVER"DRV/|1.6", MATCH_DRIVER"DR", MATCH_DRIVER"DR*"),
+ NULL);
+ _do_test_match_spec_device ("driver:DRV//*",
+ S (MATCH_DRIVER"DRV/", MATCH_DRIVER"DRV/|1.6"),
+ S (MATCH_DRIVER"DR", MATCH_DRIVER"DR*"),
+ NULL);
+ _do_test_match_spec_device ("driver:DRV//1.5*",
+ S (MATCH_DRIVER"DRV/|1.5", MATCH_DRIVER"DRV/|1.5.2"),
+ S (MATCH_DRIVER"DRV/", MATCH_DRIVER"DRV/|1.6", MATCH_DRIVER"DR", MATCH_DRIVER"DR*"),
+ NULL);
#undef S
}