mfd-hyperv 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mfd_hyperv/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Module for Hyperv."""
4
+ from .base import HyperV
@@ -0,0 +1,3 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Module for attributes of Hyper-V objects."""
@@ -0,0 +1,62 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """VMNetworkInterfaceAttributes class."""
4
+ from enum import Enum
5
+
6
+
7
+ class VMNetworkInterfaceAttributes(str, Enum):
8
+ """Attributes of VM network interface."""
9
+
10
+ def __str__(self) -> str:
11
+ return str.__str__(self)
12
+
13
+ DynamicMacAddressEnabled = "dynamicmacaddressenabled"
14
+ AllowPacketDirect = "allowpacketdirect"
15
+ NumaAwarePlacement = "numaawareplacement"
16
+ MacAddressSpoofing = "macaddressspoofing"
17
+ AllowTeaming = "allowteaming"
18
+ RouterGuard = "routerguard"
19
+ DhcpGuard = "dhcpguard"
20
+ StormLimit = "stormlimit"
21
+ PortMirroringMode = "portmirroringmode"
22
+ IeeePriorityTag = "ieeeprioritytag"
23
+ VirtualSubnetId = "virtualsubnetid"
24
+ DynamicIPAddressLimit = "dynamicipaddresslimit"
25
+ DeviceNaming = "devicename"
26
+ VmqWeight = "vmqweight"
27
+ VmqUsage = "vmqusage"
28
+ IovWeight = "iovweight"
29
+ IovUsage = "iovusage"
30
+ IovQueuePairsRequested = "iovqueuepairsrequested"
31
+ IovQueuePairsAssigned = "iovqueuepairsassigned"
32
+ IovInterruptModeration = "iovinterruptmoderation"
33
+ PacketDirectNumProcs = "packetdirectnumprocs"
34
+ PacketDirectModerationCount = "packetdirectmoderationcount"
35
+ PacketDirectModerationInterval = "packetdirectmoderationinterval"
36
+ VrssEnabledRequested = "vrssenabledrequested"
37
+ VrssEnabled = "vrssenabled"
38
+ VmmqEnabledRequested = "vmmqenabledrequested"
39
+ VmmqEnabled = "vmmqenabled"
40
+ VrssMaxQueuePairsRequested = "vrssmaxqueuepairsrequested"
41
+ VrssMaxQueuePairs = "vrssmaxqueuepairs"
42
+ VrssMinQueuePairsRequested = "vrssminqueuepairsrequested"
43
+ VrssMinQueuePairs = "vrssminqueuepairs"
44
+ VrssQueueSchedulingModeRequested = "vrssqueueschedulingmoderequested"
45
+ VrssQueueSchedulingMode = "vrssqueueschedulingmode"
46
+ VrssExcludePrimaryProcessorRequested = "vrssexcludeprimaryprocessorrequested"
47
+ VrssExcludePrimaryProcessor = "vrssexcludeprimaryprocessor"
48
+ VrssIndependentHostSpreadingRequested = "vrssindependenthostspreadingrequested"
49
+ VrssIndependentHostSpreading = "vrssindependenthostspreading"
50
+ VrssVmbusChannelAffinityPolicyRequested = "vrssvmbuschannelaffinitypolicyrequested"
51
+ VrssVmbusChannelAffinityPolicy = "vrssvmbuschannelaffinitypolicy"
52
+ RscEnabledRequested = "rscenabledrequested"
53
+ RscEnabled = "rscenabled"
54
+ IPsecOffloadMaxSA = "ipsecoffloadmaxsa"
55
+ IPsecOffloadSAUsage = "ipsecoffloadsausage"
56
+ VFDataPathActive = "vfdatapathactive"
57
+ MaximumBandwidth = "maximumbandwidth"
58
+ MinimumBandwidthAbsolute = "minimumbandwidthabsolute"
59
+ MinimumBandwidthWeight = "minimumbandwidthweight"
60
+ BandwidthPercentage = "bandwidthpercentage"
61
+ VmmqQueuePairs = "vmmqqueuepairs"
62
+ StaticMacAddress = "staticmacaddress"
@@ -0,0 +1,41 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """VMParams class."""
4
+ from dataclasses import dataclass, fields
5
+ from typing import Optional, Union
6
+
7
+ from mfd_typing import MACAddress
8
+ from mfd_typing.dataclass_utils import convert_value_field_to_typehint_type
9
+
10
+
11
+ @dataclass
12
+ class VMParams:
13
+ """Configuration for VM.
14
+
15
+ name: Name of VM
16
+ cpu_count: Count of CPUs
17
+ hw_threads_per_core: number of virtual SMT threads exposed to the virtual machine
18
+ memory: Memory value in MB
19
+ generation: Generation of VM
20
+ vm_dir_path: Path to directory where VM will be stored
21
+ img_file_name: Name of VM image used for VM
22
+ mng_interface_name: Name of management vSwitch
23
+ mng_mac_address: Mac address for management vSwitch
24
+ vswitch_name: Name of management vSwitch used
25
+ """
26
+
27
+ name: str = "vm"
28
+ cpu_count: int = 2
29
+ hw_threads_per_core: int = 0
30
+ memory: int = 2048
31
+ generation: int = 2
32
+ vm_dir_path: Optional[str] = None
33
+ diff_disk_path: Optional[str] = None
34
+ mng_interface_name: str = "mng"
35
+ mng_mac_address: Optional[Union[MACAddress, str]] = None
36
+ mng_ip: Optional[str] = None
37
+ vswitch_name: Optional[str] = None
38
+
39
+ def __post_init__(self):
40
+ for field in fields(self):
41
+ convert_value_field_to_typehint_type(self, field)
@@ -0,0 +1,14 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """VMProcessorAttributes class."""
4
+ from enum import Enum
5
+
6
+
7
+ class VMProcessorAttributes(str, Enum):
8
+ """Enum for VM processor attributes."""
9
+
10
+ def __str__(self) -> str:
11
+ return str.__str__(self)
12
+
13
+ Count: str = "count"
14
+ HWThreadCountPerCore: str = "hwthreadcountpercore"
@@ -0,0 +1,26 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """VSwitchAttributes class."""
4
+ from enum import Enum
5
+
6
+
7
+ class VSwitchAttributes(str, Enum):
8
+ """Enum of attributes that can be set on vSwitch."""
9
+
10
+ def __str__(self) -> str:
11
+ return str.__str__(self)
12
+
13
+ DefaultQueueVmmqEnabled: str = "defaultqueuevmmqenabled"
14
+ DefaultQueueVmmqQueuePairs: str = "defaultqueuevmmqqueuepairs"
15
+ EmbeddedTeamingEnabled: str = "embeddedteamingenabled"
16
+ EnableSoftwareRsc: str = "enablesoftwarersc"
17
+ EnableRscOffload: str = "enablerscoffload"
18
+ IovEnabled: str = "iovenabled"
19
+ IovQueuePairsInUse: str = "iovqueuepairsinuse"
20
+ IovSupport: str = "iovsupport"
21
+ IovVirtualFunctionCount: str = "iovvirtualfunctioncount"
22
+ IovVirtualFunctionsInUse: str = "iovvirtualfunctionsinuse"
23
+ NumberVmqAllocated: str = "numbervmqallocated"
24
+ RscOffloadEnabled: str = "rscoffloadenabled"
25
+ SoftwareRscEnabled: str = "softwarerscenabled"
26
+ SwitchType: str = "switchtype"
mfd_hyperv/base.py ADDED
@@ -0,0 +1,31 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Main module."""
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from mfd_common_libs import os_supported
8
+ from mfd_typing import OSName
9
+
10
+ from mfd_hyperv.hw_qos import HWQoS
11
+ from mfd_hyperv.hypervisor import HypervHypervisor
12
+ from mfd_hyperv.vm_network_interface_manager import VMNetworkInterfaceManager
13
+ from mfd_hyperv.vswitch_manager import VSwitchManager
14
+
15
+ if TYPE_CHECKING:
16
+ from mfd_connect import Connection
17
+
18
+
19
+ class HyperV:
20
+ """Module for HyperV."""
21
+
22
+ @os_supported(OSName.WINDOWS)
23
+ def __init__(self, *, connection: "Connection"):
24
+ """Class constructor.
25
+
26
+ :param connection: connection instance of MFD connect class.
27
+ """
28
+ self.hw_qos = HWQoS(connection)
29
+ self.hypervisor = HypervHypervisor(connection=connection)
30
+ self.vswitch_manager = VSwitchManager(connection=connection)
31
+ self.vm_network_interface_manager = VMNetworkInterfaceManager(connection=connection)
@@ -0,0 +1,12 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Module for exceptions."""
4
+ import subprocess
5
+
6
+
7
+ class HyperVException(Exception):
8
+ """Handle HyperV module exceptions."""
9
+
10
+
11
+ class HyperVExecutionException(subprocess.CalledProcessError):
12
+ """Handle execution exceptions."""
mfd_hyperv/helpers.py ADDED
@@ -0,0 +1,13 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Module for helper functions."""
4
+ from typing import Union
5
+
6
+
7
+ def standardise_value(value: Union[int, str, bool]) -> str:
8
+ """Make input value standardised, no matter it's type to make comparisons more easily."""
9
+ value = str(value)
10
+ value = value.lower()
11
+ if value in ["true", "false"]:
12
+ return f"${value}"
13
+ return value
mfd_hyperv/hw_qos.py ADDED
@@ -0,0 +1,282 @@
1
+ # Copyright (C) 2025 Intel Corporation
2
+ # SPDX-License-Identifier: MIT
3
+ """Main module."""
4
+
5
+ import logging
6
+ import re
7
+
8
+ from typing import TYPE_CHECKING
9
+ from mfd_common_libs import log_levels, add_logging_level
10
+
11
+ from mfd_hyperv.exceptions import HyperVExecutionException, HyperVException
12
+
13
+ if TYPE_CHECKING:
14
+ from mfd_connect import Connection
15
+
16
+ logger = logging.getLogger(__name__)
17
+ add_logging_level(level_name="MODULE_DEBUG", level_value=log_levels.MODULE_DEBUG)
18
+
19
+
20
+ class HWQoS:
21
+ """Class for Hyper-V Hardware QoS Offload functionality."""
22
+
23
+ def __init__(self, connection: "Connection") -> None:
24
+ """
25
+ Class constructor.
26
+
27
+ :param connection: connection instance.
28
+ """
29
+ self._connection = connection
30
+
31
+ def create_scheduler_queue(
32
+ self, vswitch_name: str, sq_id: str, sq_name: str, limit: bool, tx_max: str, tx_reserve: str, rx_max: str
33
+ ) -> None:
34
+ """
35
+ Create scheduler queue.
36
+
37
+ :param vswitch_name: name of the virtual switch.
38
+ :param sq_id: ID for new scheduler queue.
39
+ :param sq_name: name for new scheduler queue.
40
+ :param limit: determine if enforcing infra-host limits.
41
+ :param tx_max: transmit limit.
42
+ :param tx_reserve: transmit reservation.
43
+ :param rx_max: receive limit.
44
+ :raises HyperVExecutionException: when command execution fails.
45
+ """
46
+ limit = str(limit).lower()
47
+ cmd = (
48
+ f"vfpctrl /switch {vswitch_name} /add-queue " f'"{sq_id} {sq_name} {limit} {tx_max} {tx_reserve} {rx_max}"'
49
+ )
50
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
51
+
52
+ def update_scheduler_queue(
53
+ self, vswitch_name: str, limit: bool, tx_max: str, tx_reserve: str, rx_max: str, sq_id: str
54
+ ) -> None:
55
+ """
56
+ Update existing scheduler queue.
57
+
58
+ :param vswitch_name: name of the virtual switch.
59
+ :param limit: determine if enforcing infra-host limits.
60
+ :param tx_max: queue configuration value which determines transmit limit.
61
+ :param tx_reserve: transmit reservation.
62
+ :param rx_max: receive limit.
63
+ :param sq_id: ID of existing scheduler queue.
64
+ :raises HyperVExecutionException: when command execution fails.
65
+ """
66
+ limit = str(limit).lower()
67
+ cmd = (
68
+ f"vfpctrl /switch {vswitch_name} /set-queue-config "
69
+ f'"{limit} {tx_max} {tx_reserve} {rx_max}" /queue "{sq_id}"'
70
+ )
71
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
72
+
73
+ def delete_scheduler_queue(self, vswitch_name: str, sq_id: str) -> None:
74
+ """
75
+ Delete existing scheduler queue.
76
+
77
+ :param vswitch_name: name of the virtual switch.
78
+ :param sq_id: ID of existing scheduler queue.
79
+ :raises HyperVExecutionException: when command execution fails.
80
+ """
81
+ cmd = f'vfpctrl /switch {vswitch_name} /remove-queue /queue "{sq_id}"'
82
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
83
+
84
+ def get_qos_config(self, vswitch_name: str) -> dict[str, str | bool]:
85
+ """
86
+ Get current QoS configuration for the vSwitch.
87
+
88
+ :param vswitch_name: name of the virtual switch.
89
+ :return: config from parsed command output, for example:
90
+ {'hw_caps': False, 'hw_reserv': False, 'sw_reserv': True, flags: 0x0}
91
+ :raises HyperVExecutionException: when command execution fails.
92
+ """
93
+ cmd = f"vfpctrl /switch {vswitch_name} /get-qos-config"
94
+ result = self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
95
+
96
+ pattern = (
97
+ r"Caps:+\s(?P<hw_caps>\S+)[\s\S]*?"
98
+ r"Hardware Reservations:+\s(?P<hw_reserv>\S+)[\s\S]*?"
99
+ r"Software Reservations:+\s(?P<sw_reserv>\S+)[\s\S]*?"
100
+ r"Flags:+\s(?P<flags>\S+)"
101
+ )
102
+ parsed_config = {}
103
+ matches = re.finditer(pattern, result.stdout)
104
+ params = ["hw_caps", "hw_reserv", "sw_reserv", "flags"]
105
+
106
+ for match in matches:
107
+ for param in params:
108
+ if param == "flags":
109
+ parsed_config[param] = match.group(param)
110
+ else:
111
+ parsed_config[param] = True if match.group(param) == "TRUE" else False
112
+
113
+ return parsed_config
114
+
115
+ def set_qos_config(self, vswitch_name: str, hw_caps: bool, hw_reserv: bool, sw_reserv: bool, flags: str) -> None:
116
+ """
117
+ Set QoS configuration on the vSwitch.
118
+
119
+ :param vswitch_name: name of the virtual switch.
120
+ :param hw_caps: determine if enable hardware caps.
121
+ :param hw_reserv: determine if enable hardware reservations.
122
+ :param sw_reserv: determine if enable software reservations.
123
+ :param flags: flags.
124
+ :raises HyperVExecutionException: when command execution fails.
125
+ """
126
+ hw_caps = str(hw_caps).lower()
127
+ hw_reserv = str(hw_reserv).lower()
128
+ sw_reserv = str(sw_reserv).lower()
129
+ cmd = f'vfpctrl /switch {vswitch_name} /set-qos-config "{hw_caps} {hw_reserv} {sw_reserv} {flags}"'
130
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
131
+
132
+ def disassociate_scheduler_queues_with_vport(self, vswitch_name: str, vport: str) -> None:
133
+ """
134
+ Disassociate scheduler queues with virtual port.
135
+
136
+ :param vswitch_name: name of the virtual switch.
137
+ :param vport: virtual port.
138
+ :raises HyperVExecutionException: when command execution fails.
139
+ """
140
+ cmd = f"vfpctrl /switch {vswitch_name} /port {vport} /clear-port-queue"
141
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
142
+
143
+ def list_scheduler_queues_with_vport(self, vswitch_name: str, vport: str) -> list[str]:
144
+ """
145
+ List scheduler queues associated with virtual port.
146
+
147
+ :param vswitch_name: name of the virtual switch.
148
+ :param vport: virtual port.
149
+ :return: list of SQ IDs associated with given port, eg. ["1", "5", "2"]
150
+ :raises HyperVExecutionException: when command execution fails.
151
+ """
152
+ cmd = f"vfpctrl /switch {vswitch_name} /port {vport} /get-port-queue"
153
+ result = self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
154
+ pattern = r"(?<=QOS QUEUE: ).*"
155
+ return re.findall(pattern, result.stdout)
156
+
157
+ def associate_scheduler_queues_with_vport(
158
+ self, vswitch_name: str, vport: str, sq_id: str, lid: int, lname: str
159
+ ) -> None:
160
+ """
161
+ Associate scheduler queues with virtual port.
162
+
163
+ :param vswitch_name: name of the virtual switch.
164
+ :param vport: virtual port.
165
+ :param sq_id: ID of existing scheduler queue.
166
+ :param lid: layer ID
167
+ :param lname: layer name
168
+ :raises HyperVExecutionException: when any command execution fails.
169
+ """
170
+ base_cmd = f"vfpctrl /switch {vswitch_name} /port {vport}"
171
+ params = [
172
+ "/enable-port",
173
+ "/unblock-port",
174
+ f"/add-layer '{lid} {lname} stateless 100 1'",
175
+ f"/set-port-queue {sq_id}",
176
+ ]
177
+ for param in params:
178
+ cmd = f"{base_cmd} {param}"
179
+ self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
180
+
181
+ def get_vmswitch_port_name(self, switch_friendly_name: str, vm_name: str) -> str:
182
+ """
183
+ Get vmswitch port name.
184
+
185
+ :param switch_friendly_name: switch friendly name.
186
+ :param vm_name: vm name.
187
+ :return: vmswitch port name.
188
+ :raises HyperVExecutionException: when command execution fails.
189
+ :raises HyperVException: when no vmswitch port name found.
190
+ """
191
+ cmd = "vfpctrl /list-vmswitch-port"
192
+
193
+ result = self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException)
194
+
195
+ pattern = (
196
+ r"Port\sname\s+:+\s(?P<port_name>\S+)[\s\S]*?"
197
+ r"Switch\sFriendly\sname\s+:+\s(?P<friendly_name>\S+)[\s\S]*?"
198
+ r"VM\sname\s+:+\s(?P<vm_name>\S+)"
199
+ )
200
+
201
+ matches = re.finditer(pattern, result.stdout)
202
+
203
+ for match in matches:
204
+ if match.group("friendly_name") == switch_friendly_name and match.group("vm_name") == vm_name:
205
+ return match.group("port_name")
206
+
207
+ raise HyperVException(
208
+ f"Couldn't find VM Switch port name for Switch Friendly name: {switch_friendly_name} and "
209
+ f"VM name: {vm_name} in output: {result.stdout}"
210
+ )
211
+
212
+ def is_scheduler_queues_created(self, vswitch_name: str, sq_id: int, sq_name: str, tx_max: str) -> bool:
213
+ """
214
+ Verify that scheduler queues with provided name was created.
215
+
216
+ :param vswitch_name: name of vswitch.
217
+ :param sq_id: scheduler queues for verification.
218
+ :param sq_name: name of scheduler queues.
219
+ :param tx_max: transmit limit value
220
+ :return: True if SQ found, False otherwise.
221
+ :raises HyperVExecutionException: when command execution fails.
222
+ """
223
+ pattern = (
224
+ r"(?<=QOS QUEUE: )(?P<sq_id>.*)\s+"
225
+ r"Friendly\sname\s+:+\s(?P<friendly_name>\S+)[\s\S]*?\s+.+"
226
+ r"Transmit\sLimit:+\s(?P<tx_max>\S+)"
227
+ )
228
+
229
+ listed_queue = self.list_queue(vswitch_name=vswitch_name)
230
+ all_info = self.get_queue_all_info(vswitch_name=vswitch_name)
231
+ offload_info = self.get_queue_offload_info(vswitch_name=vswitch_name, sq_id=sq_id)
232
+
233
+ for result in [listed_queue, all_info, offload_info]:
234
+ matches = re.finditer(pattern, result)
235
+ for match in matches:
236
+ if (
237
+ match.group("friendly_name") == sq_name
238
+ and match.group("sq_id") == str(sq_id)
239
+ and match.group("tx_max") == str(tx_max)
240
+ ):
241
+ is_scheduler_queues_created = True
242
+ break
243
+ else:
244
+ is_scheduler_queues_created = False
245
+
246
+ return is_scheduler_queues_created
247
+
248
+ def list_queue(self, vswitch_name: str) -> str:
249
+ """
250
+ List quested scheduler queues on a vswitch.
251
+
252
+ :param vswitch_name: name of vswitch.
253
+ :return: output from command.
254
+ :raises HyperVExecutionException: when command execution fails.
255
+ """
256
+ cmd = f"vfpctrl /switch {vswitch_name} /list-queue"
257
+ return self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException).stdout
258
+
259
+ def get_queue_all_info(self, vswitch_name: str) -> str:
260
+ """
261
+ List quested scheduler queues on a vswitch.
262
+
263
+ :param vswitch_name: name of vswitch.
264
+ :return: output from command.
265
+ :raises HyperVExecutionException: when command execution fails.
266
+ """
267
+ cmd = f'vfpctrl /switch {vswitch_name} /get-queue-info "all"'
268
+
269
+ return self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException).stdout
270
+
271
+ def get_queue_offload_info(self, vswitch_name: str, sq_id: int) -> str:
272
+ """
273
+ List quested scheduler queues on a vswitch.
274
+
275
+ :param vswitch_name: name of vswitch.
276
+ :param sq_id: number of scheduler queues.
277
+ :return: output from command.
278
+ :raises HyperVExecutionException: when command execution fails.
279
+ """
280
+ cmd = f'vfpctrl /switch {vswitch_name} /get-queue-info "offload" /queue "{sq_id}"'
281
+
282
+ return self._connection.execute_powershell(command=cmd, custom_exception=HyperVExecutionException).stdout