From ab8bb2e1d525d9abb537f30f81f39359c6764036 Mon Sep 17 00:00:00 2001 From: "M. Rehan" Date: Thu, 17 Oct 2024 21:08:57 +0500 Subject: [PATCH] Better validate VM NIC mac address (cherry picked from commit 55b99033703cd2ab3d1301b2518c1cfa1fda8d7a) --- .../middlewared/plugins/vm/devices/nic.py | 4 + .../plugins/vm/test_vm_devices_validation.py | 83 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/middlewared/middlewared/pytest/unit/plugins/vm/test_vm_devices_validation.py diff --git a/src/middlewared/middlewared/plugins/vm/devices/nic.py b/src/middlewared/middlewared/plugins/vm/devices/nic.py index c33600ac7ec9c..d84c97c12a472 100644 --- a/src/middlewared/middlewared/plugins/vm/devices/nic.py +++ b/src/middlewared/middlewared/plugins/vm/devices/nic.py @@ -104,3 +104,7 @@ def _validate(self, device, verrors, old=None, vm_instance=None, update=True): 'attributes.trust_guest_rx_filters', 'This can only be set when "type" of NIC device is "VIRTIO"' ) + + mac_address = device['attributes'].get('mac') + if mac_address and mac_address.lower().startswith('ff'): + verrors.add('attributes.mac', 'MAC address must not start with `ff`') diff --git a/src/middlewared/middlewared/pytest/unit/plugins/vm/test_vm_devices_validation.py b/src/middlewared/middlewared/pytest/unit/plugins/vm/test_vm_devices_validation.py new file mode 100644 index 0000000000000..b657d2ba42380 --- /dev/null +++ b/src/middlewared/middlewared/pytest/unit/plugins/vm/test_vm_devices_validation.py @@ -0,0 +1,83 @@ +import pytest + +from middlewared.plugins.vm.devices import NIC +from middlewared.pytest.unit.middleware import Middleware + +from middlewared.service_exception import ValidationErrors + + +AVAILABLE_NIC_INTERFACES = ['br0', 'eth0'] + + +@pytest.mark.parametrize('device_data,expected_error', [ + ( + { + 'attributes': { + 'type': 'VIRTIO', + 'mac': '00:a0:99:7e:bb:8a', + 'nic_attach': 'br0', + 'trust_guest_rx_filters': False + }, + 'dtype': 'NIC', + }, + '' + ), + ( + { + 'attributes': { + 'type': 'VIRTIO', + 'mac': '00:a0:99:7e:bb:8a', + 'nic_attach': 'br2', + 'trust_guest_rx_filters': False + }, + 'dtype': 'NIC', + }, + '[EINVAL] attributes.nic_attach: Not a valid choice.' + ), + ( + { + 'attributes': { + 'type': 'VIRTIO', + 'mac': 'ff:a0:99:7e:bb:8a', + 'nic_attach': 'br0', + 'trust_guest_rx_filters': False + }, + 'dtype': 'NIC', + }, + '[EINVAL] attributes.mac: MAC address must not start with `ff`' + ), + ( + { + 'attributes': { + 'type': 'VIRTIO', + 'mac': 'ff:a0:99:7e:bb:8a', + 'nic_attach': 'br0', + 'trust_guest_rx_filters': True + }, + 'dtype': 'NIC', + }, + '[EINVAL] attributes.trust_guest_rx_filters: This can only be set when "nic_attach" is not a bridge device' + ), + ( + { + 'attributes': { + 'type': 'E1000', + 'mac': 'ff:a0:99:7e:bb:8a', + 'nic_attach': 'eth0', + 'trust_guest_rx_filters': True + }, + 'dtype': 'NIC', + }, + '[EINVAL] attributes.trust_guest_rx_filters: This can only be set when "type" of NIC device is "VIRTIO"' + ), +]) +def test_nic_device_validation(device_data, expected_error): + m = Middleware() + m['vm.device.nic_attach_choices'] = lambda *arg: AVAILABLE_NIC_INTERFACES + if expected_error: + with pytest.raises(ValidationErrors) as ve: + NIC(device_data, m).validate(device_data) + + assert str(ve.value.errors[0]) == expected_error + else: + assert NIC(device_data, m).validate(device_data) is None