summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nm.c162
-rw-r--r--tests/generator/base.py13
-rw-r--r--tests/generator/test_auth.py18
-rw-r--r--tests/generator/test_bonds.py16
-rw-r--r--tests/generator/test_bridges.py37
-rw-r--r--tests/generator/test_common.py48
-rw-r--r--tests/generator/test_ethernets.py69
-rw-r--r--tests/generator/test_modems.py30
-rw-r--r--tests/generator/test_passthrough.py28
-rw-r--r--tests/generator/test_vlans.py28
-rw-r--r--tests/generator/test_wifis.py34
11 files changed, 244 insertions, 239 deletions
diff --git a/src/nm.c b/src/nm.c
index dcab690..1b2918a 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -26,58 +26,15 @@
#include <glib/gprintf.h>
#include <uuid.h>
+#include "names.h"
#include "netplan.h"
#include "nm.h"
#include "parse.h"
#include "parse-globals.h"
+#include "parse-nm.h"
#include "util.h"
#include "util-internal.h"
#include "validation.h"
-#include "parse-nm.h"
-
-GString* udev_rules;
-
-/**
- * Append NM device specifier of @def to @s.
- */
-static void
-g_string_append_netdef_match(GString* s, const NetplanNetDefinition* def)
-{
- g_assert(!def->match.driver || def->set_name);
- if (def->match.mac || def->match.original_name || def->set_name || def->type >= NETPLAN_DEF_TYPE_VIRTUAL) {
- if (def->match.mac) {
- g_string_append_printf(s, "mac:%s,", def->match.mac);
- }
- /* MAC could change, e.g. for bond slaves. Ignore by interface-name as well */
- if (def->match.original_name || def->set_name || def->type >= NETPLAN_DEF_TYPE_VIRTUAL) {
- /* we always have the renamed name here */
- g_string_append_printf(s, "interface-name:%s,",
- (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) ? def->id
- : (def->set_name ?: def->match.original_name));
- }
- } else {
- /* no matches → match all devices of that type */
- switch (def->type) {
- case NETPLAN_DEF_TYPE_ETHERNET:
- g_string_append(s, "type:ethernet,");
- break;
- /* This cannot be reached with just NM and networkd backends, as
- * networkd does not support wifi and thus we'll never blacklist a
- * wifi device from NM. This would become relevant with another
- * wifi-supporting backend, but until then this just spoils 100%
- * code coverage.
- case NETPLAN_DEF_TYPE_WIFI:
- g_string_append(s, "type:wifi");
- break;
- */
-
- // LCOV_EXCL_START
- default:
- g_assert_not_reached();
- // LCOV_EXCL_STOP
- }
- }
-}
/**
* Infer if this is a modem netdef of type GSM.
@@ -959,49 +916,108 @@ netplan_netdef_write_nm(
return no_error;
}
-static void
-nd_append_non_nm_ids(gpointer data, gpointer str)
-{
- const NetplanNetDefinition* nd = data;
-
- if (nd->backend != NETPLAN_BACKEND_NM) {
- if (nd->match.driver) {
- /* TODO: NetworkManager supports (non-globbing) "driver:..." matching nowadays */
- /* NM cannot match on drivers, so ignore these via udev rules */
- if (!udev_rules)
- udev_rules = g_string_new(NULL);
- g_string_append_printf(udev_rules, "ACTION==\"add|change\", SUBSYSTEM==\"net\", ENV{ID_NET_DRIVER}==\"%s\", ENV{NM_UNMANAGED}=\"1\"\n", nd->match.driver);
- } else {
- g_string_append_netdef_match((GString*) str, nd);
- }
- }
-}
-
gboolean
netplan_state_finish_nm_write(
const NetplanState* np_state,
const char* rootdir,
GError** error)
{
- GString *s = NULL;
- gsize len;
+ GString* udev_rules = g_string_new(NULL);
+ GString *nm_conf = g_string_new(NULL);
if (netplan_state_get_netdefs_size(np_state) == 0)
return TRUE; // LCOV_EXCL_LINE as generate.c already deals with it.
/* Set all devices not managed by us to unmanaged, so that NM does not
- * auto-connect and interferes */
- s = g_string_new("[keyfile]\n# devices managed by networkd\nunmanaged-devices+=");
- len = s->len;
- g_list_foreach(np_state->netdefs_ordered, nd_append_non_nm_ids, s);
- if (s->len > len)
- g_string_free_to_file(s, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL);
+ * auto-connect and interferes.
+ * Also, mark all devices managed by us explicitly, so it won't get in
+ * conflict with the system's udev rules that might ignore some devices
+ * in containers via usr/lib/udev/rules.d/85-nm-unmanaged-devices.rules */
+ GList* iter = np_state->netdefs_ordered;
+ while (iter) {
+ const NetplanNetDefinition* nd = iter->data;
+ const gchar* nm_type;
+ GString *tmp = NULL;
+ guint unmanaged = nd->backend == NETPLAN_BACKEND_NM ? 0 : 1;
+
+ /* Special case: manage or ignore any device of given type on empty "match: {}" stanza */
+ if (nd->has_match && !nd->match.driver && !nd->match.mac && !nd->match.original_name) {
+ nm_type = type_str(nd);
+ g_assert(nm_type);
+ g_string_append_printf(nm_conf, "[device-netplan.%s.%s]\nmatch-device=type:%s\n"
+ "managed=%d\n\n", netplan_def_type_name(nd->type),
+ nd->id, nm_type, !unmanaged);
+ }
+ /* Normal case: manage or ignore devices by specific udev rules */
+ else {
+ const gchar *prefix = "SUBSYSTEM==\"net\", ACTION==\"add|change|move\",";
+ const gchar *suffix = nd->backend == NETPLAN_BACKEND_NM ? " ENV{NM_UNMANAGED}=\"0\"\n" : " ENV{NM_UNMANAGED}=\"1\"\n";
+ g_string_append_printf(udev_rules, "# netplan: network.%s.%s (on NetworkManager %s)\n",
+ netplan_def_type_name(nd->type), nd->id,
+ unmanaged ? "deny-list" : "allow-list");
+ /* Match by explicit interface name, if possible */
+ if (nd->set_name) {
+ // simple case: explicit new interface name
+ g_string_append_printf(udev_rules, "%s ENV{ID_NET_NAME}==\"%s\",%s", prefix, nd->set_name, suffix);
+ } else if (!nd->has_match) {
+ // simple case: explicit netplan ID is interface name
+ g_string_append_printf(udev_rules, "%s ENV{ID_NET_NAME}==\"%s\",%s", prefix, nd->id, suffix);
+ }
+ /* Also, match by explicit (new) MAC, if available */
+ if (nd->set_mac) {
+ tmp = g_string_new(nd->set_mac);
+ g_string_append_printf(udev_rules, "%s ATTR{address}==\"%s\",%s", prefix, g_string_ascii_down(tmp)->str, suffix);
+ g_string_free(tmp, TRUE);
+ }
+ /* Finally, add a full match, using all rules & globs available
+ * from the "match" stanza (e.g. original_name/mac/drivers)
+ * This will match the "old" interface (i.e. original MAC and/or
+ * interface name) if it got changed */
+ if (nd->has_match && (nd->match.original_name || nd->match.mac || nd->match.driver)) {
+ // match on original name glob
+ // TODO: maybe support matching on multiple name globs in the future (like drivers)
+ g_string_append(udev_rules, prefix);
+ if (nd->match.original_name)
+ g_string_append_printf(udev_rules, " ENV{ID_NET_NAME}==\"%s\",", nd->match.original_name);
+
+ // match on (explicit) MAC address. Yes this would be unique on its own, but we
+ // keep it within the "full match" to make the logic more comprehensible.
+ if (nd->match.mac) {
+ tmp = g_string_new(nd->match.mac);
+ g_string_append_printf(udev_rules, " ATTR{address}==\"%s\",", g_string_ascii_down(tmp)->str);
+ g_string_free(tmp, TRUE);
+ }
+
+ // match on (multiple) driver globs
+ if (nd->match.driver) {
+ gchar *drivers = NULL;
+ if (strchr(nd->match.driver, '\t')) {
+ gchar **split = g_strsplit(nd->match.driver, "\t", -1);
+ drivers = g_strjoinv("|", split);
+ g_strfreev(split);
+ } else
+ drivers = g_strdup(nd->match.driver);
+ g_string_append_printf(udev_rules, " ENV{ID_NET_DRIVER}==\"%s\",", drivers);
+ g_free(drivers);
+ }
+ g_string_append(udev_rules, suffix);
+ }
+ }
+ iter = iter->next;
+ }
+
+ /* write generated NetworkManager drop-in config */
+ if (nm_conf->len > 0)
+ g_string_free_to_file(nm_conf, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL);
else
- g_string_free(s, TRUE);
+ g_string_free(nm_conf, TRUE);
/* write generated udev rules */
- if (udev_rules)
+ if (udev_rules->len > 0)
g_string_free_to_file(udev_rules, rootdir, "run/udev/rules.d/90-netplan.rules", NULL);
+ else
+ g_string_free(udev_rules, TRUE);
+
return TRUE;
}
diff --git a/tests/generator/base.py b/tests/generator/base.py
index 689c4e0..f0407c9 100644
--- a/tests/generator/base.py
+++ b/tests/generator/base.py
@@ -92,6 +92,12 @@ Wants=network.target
Type=simple
ExecStart=/sbin/wpa_supplicant -c /run/netplan/wpa-%(iface)s.conf -i%(iface)s -D%(drivers)s
'''
+NM_MANAGED = 'SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_NAME}=="%s", ENV{NM_UNMANAGED}="0"\n'
+NM_UNMANAGED = 'SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_NAME}=="%s", ENV{NM_UNMANAGED}="1"\n'
+NM_MANAGED_MAC = 'SUBSYSTEM=="net", ACTION=="add|change|move", ATTR{address}=="%s", ENV{NM_UNMANAGED}="0"\n'
+NM_UNMANAGED_MAC = 'SUBSYSTEM=="net", ACTION=="add|change|move", ATTR{address}=="%s", ENV{NM_UNMANAGED}="1"\n'
+NM_MANAGED_DRIVER = 'SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_DRIVER}=="%s", ENV{NM_UNMANAGED}="0"\n'
+NM_UNMANAGED_DRIVER = 'SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_DRIVER}=="%s", ENV{NM_UNMANAGED}="1"\n'
class NetplanV2Normalizer():
@@ -432,7 +438,12 @@ class TestBase(unittest.TestCase):
self.assertFalse(os.path.exists(rule_path))
return
with open(rule_path) as f:
- self.assertEqual(f.read(), contents)
+ lines = []
+ for line in f.readlines():
+ # ignore any comment in udev rules.d file
+ if not line.startswith('#'):
+ lines.append(line)
+ self.assertEqual(''.join(lines), contents)
def assert_ovs(self, file_contents_map):
systemd_dir = os.path.join(self.workdir.name, 'run', 'systemd', 'system')
diff --git a/tests/generator/test_auth.py b/tests/generator/test_auth.py
index 3d20109..e8fd023 100644
--- a/tests/generator/test_auth.py
+++ b/tests/generator/test_auth.py
@@ -19,7 +19,7 @@
import os
import stat
-from .base import TestBase, ND_DHCP4, ND_WIFI_DHCP4, SD_WPA
+from .base import TestBase, ND_DHCP4, ND_WIFI_DHCP4, SD_WPA, NM_MANAGED, NM_UNMANAGED
class TestNetworkd(TestBase):
@@ -83,10 +83,8 @@ class TestNetworkd(TestBase):
''')
self.assert_networkd({'wl0.network': ND_WIFI_DHCP4 % 'wl0'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:wl0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'wl0')
# generates wpa config and enables wpasupplicant unit
with open(os.path.join(self.workdir.name, 'run/netplan/wpa-wl0.conf')) as f:
@@ -201,10 +199,8 @@ network={
''')
self.assert_networkd({'eth0.network': ND_DHCP4 % 'eth0'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth0')
# generates wpa config and enables wpasupplicant unit
with open(os.path.join(self.workdir.name, 'run/netplan/wpa-eth0.conf')) as f:
@@ -458,7 +454,7 @@ method=ignore
ssid=peer2peer
mode=adhoc
'''})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'wl0')
def test_auth_wired(self):
self.generate('''network:
@@ -502,7 +498,7 @@ private-key=/etc/ssl/cust-key.pem
private-key-password=d3cryptPr1v4t3K3y
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
class TestConfigErrors(TestBase):
diff --git a/tests/generator/test_bonds.py b/tests/generator/test_bonds.py
index fea475e..ee3f53c 100644
--- a/tests/generator/test_bonds.py
+++ b/tests/generator/test_bonds.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from .base import TestBase
+from .base import TestBase, NM_MANAGED, NM_UNMANAGED
class TestNetworkd(TestBase):
@@ -79,10 +79,8 @@ ConfigureWithoutCarrier=yes
RouteMetric=100
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:bn0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'bn0')
def test_bond_components(self):
self.generate('''network:
@@ -460,7 +458,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'bn0')
def test_bond_empty_params(self):
self.generate('''network:
@@ -521,7 +519,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'bn0')
def test_bond_with_params(self):
self.generate('''network:
@@ -625,7 +623,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'bn0')
def test_bond_primary_slave(self):
self.generate('''network:
@@ -692,7 +690,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'bn0')
class TestConfigErrors(TestBase):
diff --git a/tests/generator/test_bridges.py b/tests/generator/test_bridges.py
index 7898cbe..102d592 100644
--- a/tests/generator/test_bridges.py
+++ b/tests/generator/test_bridges.py
@@ -19,7 +19,7 @@
import os
import unittest
-from .base import TestBase
+from .base import TestBase, NM_UNMANAGED, NM_MANAGED
class TestNetworkd(TestBase):
@@ -108,10 +108,8 @@ ConfigureWithoutCarrier=yes
RouteMetric=100
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:br0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'br0')
def test_bridge_type_renderer(self):
self.generate('''network:
@@ -135,10 +133,8 @@ ConfigureWithoutCarrier=yes
RouteMetric=100
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:br0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'br0')
def test_bridge_def_renderer(self):
self.generate('''network:
@@ -165,10 +161,8 @@ ConfigureWithoutCarrier=yes
RouteMetric=100
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:br0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'br0')
def test_bridge_forward_declaration(self):
self.generate('''network:
@@ -215,9 +209,8 @@ UseMTU=true
mybr:
interfaces: [ethbr]
dhcp4: yes''')
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth42,interface-name:eth43,interface-name:mybr,''')
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth42' + NM_UNMANAGED % 'eth43' + NM_UNMANAGED % 'mybr')
def test_bridge_components(self):
self.generate('''network:
@@ -322,7 +315,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'br0')
def test_bridge_type_renderer(self):
self.generate('''network:
@@ -345,7 +338,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'br0')
def test_bridge_set_mac(self):
self.generate('''network:
@@ -395,7 +388,7 @@ address1=1.2.3.4/12
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'br0')
def test_bridge_forward_declaration(self):
self.generate('''network:
@@ -456,7 +449,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'br0' + NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1')
def test_bridge_components(self):
self.generate('''network:
@@ -516,7 +509,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'br0')
def test_bridge_params(self):
self.generate('''network:
@@ -599,7 +592,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eno1' + NM_MANAGED % 'enp2s1' + NM_MANAGED % 'br0')
class TestNetplanYAMLv2(TestBase):
diff --git a/tests/generator/test_common.py b/tests/generator/test_common.py
index f4bd7f4..18467ef 100644
--- a/tests/generator/test_common.py
+++ b/tests/generator/test_common.py
@@ -19,7 +19,7 @@
import os
import textwrap
-from .base import TestBase, ND_DHCP4, ND_DHCP6, ND_DHCPYES, ND_EMPTY
+from .base import TestBase, ND_DHCP4, ND_DHCP6, ND_DHCPYES, ND_EMPTY, NM_MANAGED, NM_UNMANAGED
class TestNetworkd(TestBase):
@@ -184,10 +184,8 @@ Bond=bond0
dhcp4: true''')
self.assert_networkd({'eth0.network': ND_DHCP4 % 'eth0'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth0')
# should not allow NM to manage everything
self.assertFalse(os.path.exists(self.nm_enable_all_conf))
@@ -201,12 +199,10 @@ unmanaged-devices+=interface-name:eth0,''')
dhcp4: true''')
self.assert_networkd({'eth0.network': ND_DHCP4 % 'eth0'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth0,''')
+ self.assert_nm(None)
# should allow NM to manage everything else
self.assertTrue(os.path.exists(self.nm_enable_all_conf))
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth0')
def test_eth_def_renderer(self):
self.generate('''network:
@@ -220,10 +216,8 @@ unmanaged-devices+=interface-name:eth0,''')
self.assert_networkd({'eth0.network': ND_DHCP4 % 'eth0'})
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth0')
def test_eth_dhcp6(self):
self.generate('''network:
@@ -931,7 +925,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
def test_ipv6_mtu(self):
self.generate(textwrap.dedent("""
@@ -966,7 +960,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
def test_eth_type_renderer(self):
self.generate('''network:
@@ -992,7 +986,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
def test_eth_def_renderer(self):
self.generate('''network:
@@ -1018,7 +1012,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
def test_global_renderer_only(self):
self.generate(None, confs={'01-default-nm.yaml': 'network: {version: 2, renderer: NetworkManager}'})
@@ -1193,7 +1187,7 @@ address1=2001:FFfe::1/64
ip6-privacy=0
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'engreen')
def test_eth_manual_addresses_dhcp(self):
self.generate('''network:
@@ -1545,10 +1539,8 @@ class TestMerging(TestBase):
confs={'backend': 'network:\n renderer: networkd'})
self.assert_networkd({'engreen.network': ND_DHCP4 % 'engreen'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:engreen,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'engreen')
def test_add_def(self):
self.generate('''network:
@@ -1568,10 +1560,8 @@ unmanaged-devices+=interface-name:engreen,''')
# releases, so we can't depend on the exact order.
# TODO: (cyphermox) turn this into an "assert_in_nm()" function.
if "CODECOV_TOKEN" not in os.environ: # pragma: nocover
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:engreen,interface-name:enblue,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'engreen' + NM_UNMANAGED % 'enblue')
def test_change_def(self):
self.generate('''network:
@@ -1608,10 +1598,8 @@ unmanaged-devices+=interface-name:engreen,interface-name:enblue,''')
engreen: {dhcp4: true}''')
self.assert_networkd({'engreen.network': ND_DHCP4 % 'engreen'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:engreen,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'engreen')
def test_ref(self):
self.generate('''network:
diff --git a/tests/generator/test_ethernets.py b/tests/generator/test_ethernets.py
index e81941b..4d3f7d0 100644
--- a/tests/generator/test_ethernets.py
+++ b/tests/generator/test_ethernets.py
@@ -18,7 +18,9 @@
import os
-from .base import TestBase, ND_DHCP4, UDEV_MAC_RULE, UDEV_NO_MAC_RULE, UDEV_SRIOV_RULE
+from .base import TestBase, ND_DHCP4, UDEV_MAC_RULE, UDEV_NO_MAC_RULE, UDEV_SRIOV_RULE, \
+ NM_MANAGED, NM_UNMANAGED, NM_MANAGED_MAC, NM_UNMANAGED_MAC, \
+ NM_MANAGED_DRIVER, NM_UNMANAGED_DRIVER
class TestNetworkd(TestBase):
@@ -39,10 +41,8 @@ Name=eth0
LinkLocalAddressing=ipv6
'''})
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:eth0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'eth0')
# should not allow NM to manage everything
self.assertFalse(os.path.exists(self.nm_enable_all_conf))
@@ -140,8 +140,8 @@ LinkLocalAddressing=ipv6
'''})
self.assert_networkd_udev({'def1.rules': (UDEV_NO_MAC_RULE % ('ixgbe', 'lom1'))})
# NM cannot match by driver, so blacklisting needs to happen via udev
- self.assert_nm(None, None)
- self.assert_nm_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n')
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'lom1' + NM_UNMANAGED_DRIVER % 'ixgbe')
def test_eth_match_by_mac_rename(self):
self.generate('''network:
@@ -161,10 +161,8 @@ Name=lom1
LinkLocalAddressing=ipv6
'''})
self.assert_networkd_udev({'def1.rules': (UDEV_MAC_RULE % ('?*', '11:22:33:44:55:66', 'lom1'))})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=mac:11:22:33:44:55:66,interface-name:lom1,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'lom1' + NM_UNMANAGED_MAC % '11:22:33:44:55:66')
def test_eth_implicit_name_match_dhcp4(self):
self.generate('''network:
@@ -197,7 +195,7 @@ RouteMetric=100
UseMTU=true
'''})
self.assert_networkd_udev(None)
- self.assert_nm_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n')
+ self.assert_nm_udev(NM_UNMANAGED_DRIVER % 'ixgbe')
def test_eth_match_name(self):
self.generate('''network:
@@ -210,10 +208,8 @@ UseMTU=true
self.assert_networkd({'def1.network': ND_DHCP4 % 'green'})
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:green,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'green')
def test_eth_set_mac(self):
self.generate('''network:
@@ -247,9 +243,8 @@ unmanaged-devices+=interface-name:green,''')
# The udev rules engine does support renaming by name
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:blue,''')
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'blue' + NM_UNMANAGED % 'green')
def test_eth_match_all_names(self):
self.generate('''network:
@@ -261,10 +256,8 @@ unmanaged-devices+=interface-name:blue,''')
self.assert_networkd({'def1.network': ND_DHCP4 % '*'})
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:*,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % '*')
def test_eth_match_all(self):
self.generate('''network:
@@ -277,9 +270,9 @@ unmanaged-devices+=interface-name:*,''')
self.assert_networkd({'def1.network': '[Match]\n\n[Network]\nDHCP=ipv4\nLinkLocalAddressing=ipv6\n\n'
'[DHCP]\nRouteMetric=100\nUseMTU=true\n'})
self.assert_networkd_udev(None)
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=type:ethernet,''')
+ self.assert_nm(None, '''[device-netplan.ethernets.def1]
+match-device=type:ethernet
+managed=0\n\n''')
self.assert_nm_udev(None)
def test_match_multiple(self):
@@ -303,9 +296,9 @@ LinkLocalAddressing=ipv6
RouteMetric=100
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=mac:00:11:22:33:44:55,interface-name:en1s*,''')
+ self.assert_nm(None)
+ self.assert_nm_udev('SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_NAME}=="en1s*", '
+ 'ATTR{address}=="00:11:22:33:44:55", ENV{NM_UNMANAGED}="1"\n')
class TestNetworkManager(TestBase):
@@ -335,7 +328,7 @@ method=ignore
# should allow NM to manage everything else
self.assertTrue(os.path.exists(self.nm_enable_all_conf))
self.assert_networkd({'eth0.link': '[Match]\nOriginalName=eth0\n\n[Link]\nWakeOnLan=magic\n'})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'eth0')
def test_eth_mtu(self):
self.generate('''network:
@@ -547,7 +540,7 @@ method=link-local
[ipv6]
method=ignore
'''})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'lom1' + NM_MANAGED_DRIVER % 'ixgbe')
def test_eth_match_by_mac_rename(self):
self.generate('''network:
@@ -575,7 +568,7 @@ method=link-local
[ipv6]
method=ignore
'''})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'lom1' + NM_MANAGED_MAC % '11:22:33:44:55:66')
def test_eth_implicit_name_match_dhcp4(self):
self.generate('''network:
@@ -652,7 +645,7 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'green')
def test_eth_match_name_rename(self):
self.generate('''network:
@@ -685,7 +678,7 @@ method=ignore
'''})
# ... while udev renames it
self.assert_networkd({'def1.link': '[Match]\nOriginalName=green\n\n[Link]\nName=blue\nWakeOnLan=off\n'})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'blue' + NM_MANAGED % 'green')
def test_eth_match_name_glob(self):
self.generate('''network:
@@ -735,7 +728,10 @@ method=auto
[ipv6]
method=ignore
-'''})
+'''}, '''[device-netplan.ethernets.def1]
+match-device=type:ethernet
+managed=1\n\n''')
+ self.assert_nm_udev(None)
self.assert_networkd({})
def test_match_multiple(self):
@@ -764,7 +760,8 @@ method=auto
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev('SUBSYSTEM=="net", ACTION=="add|change|move", ENV{ID_NET_NAME}=="engreen", '
+ 'ATTR{address}=="00:11:22:33:44:55", ENV{NM_UNMANAGED}="0"\n')
def test_offload(self):
self.generate('''network:
diff --git a/tests/generator/test_modems.py b/tests/generator/test_modems.py
index acffe87..b66144e 100644
--- a/tests/generator/test_modems.py
+++ b/tests/generator/test_modems.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from .base import TestBase
+from .base import TestBase, NM_MANAGED
class TestNetworkd(TestBase):
@@ -67,7 +67,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_auto_config(self):
self.generate('''network:
@@ -91,7 +91,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_auto_config_implicit(self):
self.generate('''network:
@@ -120,7 +120,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_apn(self):
self.generate('''network:
@@ -144,7 +144,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_apn_username_password(self):
self.generate('''network:
@@ -172,7 +172,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_device_id(self):
self.generate('''network:
@@ -197,7 +197,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_network_id(self):
self.generate('''network:
@@ -222,7 +222,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_pin(self):
self.generate('''network:
@@ -247,7 +247,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_sim_id(self):
self.generate('''network:
@@ -272,7 +272,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_sim_operator_id(self):
self.generate('''network:
@@ -297,7 +297,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_gsm_example(self):
self.generate('''network:
@@ -339,7 +339,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'cdc-wdm1')
def test_modem_nm_integration(self):
self.generate('''network:
@@ -366,7 +366,7 @@ method=link-local
method=ignore
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'mobilephone')
def test_modem_nm_integration_gsm_cdma(self):
self.generate('''network:
@@ -421,6 +421,8 @@ method=auto
[ipv6]
#Netplan: passthrough override
method=auto
-'''})
+'''}, '''[device-netplan.modems.NM-a08c5805-7cf5-43f7-afb9-12cb30f6eca3]
+match-device=type:gsm
+managed=1\n\n''')
self.assert_networkd({})
self.assert_nm_udev(None)
diff --git a/tests/generator/test_passthrough.py b/tests/generator/test_passthrough.py
index 8d03c92..4af80d6 100644
--- a/tests/generator/test_passthrough.py
+++ b/tests/generator/test_passthrough.py
@@ -56,7 +56,9 @@ method=link-local
[ipv6]
method=ignore
-'''})
+'''}, '''[device-netplan.ethernets.NM-87749f1d-334f-40b2-98d4-55db58965f5f]
+match-device=type:ethernet
+managed=1\n\n''')
def test_passthrough_wifi(self):
self.generate('''network:
@@ -107,7 +109,9 @@ method=ignore
ssid=OTHER-SSID
mode=infrastructure
hidden=true
-'''})
+'''}, '''[device-netplan.wifis.NM-87749f1d-334f-40b2-98d4-55db58965f5f]
+match-device=type:wifi
+managed=1\n\n''')
def test_passthrough_type_nm_devices(self):
self.generate('''network:
@@ -132,7 +136,9 @@ method=link-local
[ipv6]
method=ignore
-'''})
+'''}, '''[device-netplan.nm-devices.NM-87749f1d-334f-40b2-98d4-55db58965f5f]
+match-device=type:dummy
+managed=1\n\n''')
def test_passthrough_dotted_group(self):
self.generate('''network:
@@ -159,7 +165,9 @@ method=ignore
[wireguard-peer.some-key]
#Netplan: passthrough setting
endpoint=1.2.3.4
-'''})
+'''}, '''[device-netplan.nm-devices.dotted-group-test]
+match-device=type:wireguard
+managed=1\n\n''')
def test_passthrough_dotted_key(self):
self.generate('''network:
@@ -193,7 +201,9 @@ qdisc.root=something
qdisc.fff1=:abc
#Netplan: passthrough setting
filters.test=test
-'''})
+'''}, '''[device-netplan.ethernets.dotted-key-test]
+match-device=type:ethernet
+managed=1\n\n''')
def test_passthrough_unsupported_setting(self):
self.generate('''network:
@@ -221,7 +231,9 @@ method=ignore
ssid=SOME-SSID
#Netplan: passthrough override
mode=mesh
-'''})
+'''}, '''[device-netplan.wifis.test]
+match-device=type:wifi
+managed=1\n\n''')
def test_passthrough_empty_group(self):
self.generate('''network:
@@ -247,7 +259,9 @@ method=link-local
method=ignore
[proxy]
-'''})
+'''}, '''[device-netplan.ethernets.test]
+match-device=type:ethernet
+managed=1\n\n''')
def test_passthrough_interface_rename_existing_id(self):
self.generate('''network:
diff --git a/tests/generator/test_vlans.py b/tests/generator/test_vlans.py
index f728d35..012295e 100644
--- a/tests/generator/test_vlans.py
+++ b/tests/generator/test_vlans.py
@@ -20,7 +20,8 @@ import os
import re
import unittest
-from .base import TestBase, ND_VLAN, ND_EMPTY, ND_WITHIP, ND_DHCP6_WOCARRIER
+from .base import TestBase, ND_VLAN, ND_EMPTY, ND_WITHIP, ND_DHCP6_WOCARRIER, \
+ NM_MANAGED, NM_UNMANAGED, NM_MANAGED_MAC, NM_UNMANAGED_MAC
class TestNetworkd(TestBase):
@@ -66,10 +67,9 @@ Id=3
.replace('[Network]', '[Link]\nMACAddress=aa:bb:cc:dd:ee:11\n\n[Network]'),
'engreen.network': (ND_DHCP6_WOCARRIER % 'engreen')})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:en1,interface-name:enblue,interface-name:enred,interface-name:engreen,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'en1' + NM_UNMANAGED % 'enblue' + NM_UNMANAGED % 'enred' +
+ NM_UNMANAGED_MAC % 'aa:bb:cc:dd:ee:11' + NM_UNMANAGED % 'engreen')
def test_vlan_sriov(self):
# we need to make sure renderer: sriov vlans are not saved as part of
@@ -95,10 +95,8 @@ VLAN=engreen
'engreen.netdev': ND_VLAN % ('engreen', 2),
'engreen.network': (ND_DHCP6_WOCARRIER % 'engreen')})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:en1,interface-name:enblue,interface-name:engreen,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'en1' + NM_UNMANAGED % 'enblue' + NM_UNMANAGED % 'engreen')
# see LP: #1888726
def test_vlan_parent_match(self):
@@ -137,10 +135,8 @@ MTUBytes=9000
'vlan20.network': ND_EMPTY % ('vlan20', 'ipv6'),
'vlan20.netdev': ND_VLAN % ('vlan20', 20)})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=mac:11:22:33:44:55:66,interface-name:lan,interface-name:vlan20,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'lan' + NM_UNMANAGED_MAC % '11:22:33:44:55:66' + NM_UNMANAGED % 'vlan20')
class TestNetworkManager(TestBase):
@@ -205,7 +201,7 @@ method=link-local
method=auto
ip6-privacy=0
'''})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'en1' + NM_MANAGED % 'enblue' + NM_MANAGED % 'engreen')
def test_vlan_parent_match(self):
self.generate('''network:
@@ -256,7 +252,7 @@ method=auto
[ipv6]
method=ignore
''' % uuid})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED_MAC % '11:22:33:44:55:66' + NM_MANAGED % 'engreen')
def test_vlan_sriov(self):
# we need to make sure renderer: sriov vlans are not saved as part of
@@ -305,4 +301,4 @@ method=link-local
method=auto
ip6-privacy=0
'''})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'en1' + NM_MANAGED % 'enblue' + NM_MANAGED % 'engreen')
diff --git a/tests/generator/test_wifis.py b/tests/generator/test_wifis.py
index 1a4ead2..bcc4cea 100644
--- a/tests/generator/test_wifis.py
+++ b/tests/generator/test_wifis.py
@@ -19,7 +19,7 @@
import os
import stat
-from .base import TestBase, ND_WIFI_DHCP4, SD_WPA
+from .base import TestBase, ND_WIFI_DHCP4, SD_WPA, NM_MANAGED, NM_UNMANAGED
class TestNetworkd(TestBase):
@@ -57,10 +57,8 @@ class TestNetworkd(TestBase):
dhcp4: yes''')
self.assert_networkd({'wl0.network': ND_WIFI_DHCP4 % 'wl0'})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:wl0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'wl0')
# generates wpa config and enables wpasupplicant unit
with open(os.path.join(self.workdir.name, 'run/netplan/wpa-wl0.conf')) as f:
@@ -240,10 +238,8 @@ RouteMetric=600
UseMTU=true
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:wl0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'wl0')
def test_wifi_match(self):
err = self.generate('''network:
@@ -292,10 +288,8 @@ Name=wl0
[Network]
LinkLocalAddressing=ipv6
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:wl0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'wl0')
# generates wpa config and enables wpasupplicant unit
with open(os.path.join(self.workdir.name, 'run/netplan/wpa-wl0.conf')) as f:
@@ -328,10 +322,8 @@ Name=wl0
[Network]
LinkLocalAddressing=ipv6
'''})
- self.assert_nm(None, '''[keyfile]
-# devices managed by networkd
-unmanaged-devices+=interface-name:wl0,''')
- self.assert_nm_udev(None)
+ self.assert_nm(None)
+ self.assert_nm_udev(NM_UNMANAGED % 'wl0')
# generates wpa config and enables wpasupplicant unit
with open(os.path.join(self.workdir.name, 'run/netplan/wpa-wl0.conf')) as f:
@@ -495,7 +487,7 @@ mode=infrastructure
band=a
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'wl0')
def test_wifi_match_mac(self):
self.generate('''network:
@@ -547,7 +539,9 @@ method=ignore
[wifi]
ssid=workplace
mode=infrastructure
-'''})
+'''}, '''[device-netplan.wifis.all]
+match-device=type:wifi
+managed=1\n\n''')
def test_wifi_ap(self):
self.generate('''network:
@@ -580,7 +574,7 @@ key-mgmt=wpa-psk
psk=s0s3cret
'''})
self.assert_networkd({})
- self.assert_nm_udev(None)
+ self.assert_nm_udev(NM_MANAGED % 'wl0')
def test_wifi_adhoc(self):
self.generate('''network: