Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/netplan-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ Match devices by MAC when setting options like: `wakeonlan` or `*-offload`.
> "XX:XX:XX:XX:XX:XX". The following special options are also accepted:
> `permanent` and `random`.
> In addition to these options, the NetworkManager renderer also accepts
> `stable` and `preserve`.
> `stable`, `stable-ssid` (Wi-Fi only) and `preserve`.
>
> **Note:** This will not work reliably for devices matched by name
> only and rendered by networkd, due to interactions with device
Expand Down
4 changes: 2 additions & 2 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ handle_special_macaddress_option(NetplanParser* npp, yaml_node_t* node, void* en
g_assert(entryptr != NULL);
g_assert(node->type == YAML_SCALAR_NODE);

if (!_is_macaddress_special_nm_option(scalar(node)) &&
if (!_is_macaddress_special_nm_option(npp->current.netdef, scalar(node)) &&
!_is_macaddress_special_nd_option(scalar(node)))
return FALSE;

Expand Down Expand Up @@ -695,7 +695,7 @@ handle_netdef_set_mac(NetplanParser* npp, yaml_node_t* node, const void* data, G
if (!handle_special_macaddress_option(npp, node, npp->current.netdef, data, NULL)) {
return yaml_error(npp, node, error,
"Invalid MAC address '%s', must be XX:XX:XX:XX:XX:XX, XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"
" or one of 'permanent', 'random', 'stable', 'preserve'.",
" or one of 'permanent', 'random', 'stable', 'preserve', 'stable-ssid' (Wi-Fi only).",
scalar(node));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/util-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ gboolean
_is_auth_key_management_psk(const NetplanAuthenticationSettings* auth);

gboolean
_is_macaddress_special_nm_option(const char* value);
_is_macaddress_special_nm_option(const NetplanNetDefinition* netdef, const char* value);

gboolean
_is_macaddress_special_nd_option(const char* value);
Expand Down
5 changes: 3 additions & 2 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1239,12 +1239,13 @@ _is_auth_key_management_psk(const NetplanAuthenticationSettings* auth)
}

gboolean
_is_macaddress_special_nm_option(const char* value)
_is_macaddress_special_nm_option(const NetplanNetDefinition* netdef, const char* value)
{
return ( !g_strcmp0(value, "preserve")
|| !g_strcmp0(value, "permanent")
|| !g_strcmp0(value, "random")
|| !g_strcmp0(value, "stable"));
|| !g_strcmp0(value, "stable")
|| (!g_strcmp0(value, "stable-ssid") && netdef->type == NETPLAN_DEF_TYPE_WIFI));
}

gboolean
Expand Down
16 changes: 15 additions & 1 deletion tests/generator/test_ethernets.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,21 @@ def test_eth_set_mac_special_values_error(self):

error = ("Invalid MAC address 'preservetypo', must be XX:XX:XX:XX:XX:XX, "
"XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX or "
"one of 'permanent', 'random', 'stable', 'preserve'")
"one of 'permanent', 'random', 'stable', 'preserve', 'stable-ssid' (Wi-Fi only)")
self.assertIn(error, res)

def test_eth_set_mac_special_values_ethernet_stable_ssid(self):
res = self.generate('''network:
version: 2
renderer: NetworkManager
ethernets:
eth0:
macaddress: stable-ssid
dhcp4: true''', expect_fail=True)

error = ("Invalid MAC address 'stable-ssid', must be XX:XX:XX:XX:XX:XX, "
"XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX or "
"one of 'permanent', 'random', 'stable', 'preserve', 'stable-ssid' (Wi-Fi only)")
self.assertIn(error, res)

def test_eth_match_by_driver(self):
Expand Down
36 changes: 36 additions & 0 deletions tests/generator/test_wifis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,42 @@ def test_wifi_regdom(self):
new_config = f.read()
self.assertIn('ExecStart=/usr/sbin/iw reg set DE\n', new_config)

def test_wlan_set_mac_special_values(self):
self.generate('''network:
version: 2
renderer: NetworkManager
wifis:
wlan0:
macaddress: stable-ssid
dhcp4: true
access-points:
"mynetwork":
password: mypassword''')

self.assert_networkd(None)

self.assert_nm({'wlan0-mynetwork': '''[connection]
id=netplan-wlan0-mynetwork
type=wifi
interface-name=wlan0

[wifi]
cloned-mac-address=stable-ssid
ssid=mynetwork
mode=infrastructure

[ipv4]
method=auto

[ipv6]
method=ignore

[wifi-security]
key-mgmt=wpa-psk
pmf=2
psk=mypassword
'''})


class TestConfigErrors(TestBase):

Expand Down
40 changes: 40 additions & 0 deletions tests/integration/wifi.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,45 @@ def test_wifi_ap_open(self):
self.assertIn('ssid fake net', out)
self.assert_iface_up(self.dev_w_ap, ['inet 10.'])

@unittest.skip("Test if flaky. NM might generate a different MAC address.")
def test_wifi_cloned_macaddress_stable_ssid(self):
self.setup_ap('''hw_mode=g
channel=1
ssid=fake net
wpa=1
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
wpa_passphrase=12345678
''', None)

with open(self.config, 'w') as f:
f.write('''network:
renderer: NetworkManager
wifis:
%(wc)s:
addresses: ["192.168.1.42/24"]
dhcp4: false
dhcp6: false
macaddress: stable-ssid
access-points:
"fake net":
password: 12345678''' % {'wc': self.dev_w_client})

subprocess.check_call(['systemctl', 'start', 'NetworkManager'])

# Make the generated MAC address predictable
# See nm_utils_hw_addr_gen_stable_eth() in NM for details
# TODO: save and restore these files to avoid any impact on the
# entire test suite.
with open('/etc/machine-id', 'w') as f:
f.write('ee7ac3602b6306061bd984a41eb1c045\n')
with open('/var/lib/NetworkManager/secret_key', 'w') as f:
f.write('nm-v2:hnIHoHp4p9kaEWU5/+dO+gFREirN1AsMoO1MPaoYxCc=')

subprocess.check_call(['systemctl', 'restart', 'NetworkManager'])

self.generate_and_settle([self.state_up(self.dev_w_client)])
self.assert_iface_up(self.dev_w_client, ['ether 5e:ba:fe:fd:89:03'])


unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
Loading