14
14
import abc
15
15
import re
16
16
import string
17
+ import typing as ty
17
18
18
19
from nova import exception
19
20
from nova .i18n import _
21
+ from nova import objects
20
22
from nova .pci import utils
21
23
22
24
MAX_VENDOR_ID = 0xFFFF
29
31
REGEX_ANY = '.*'
30
32
31
33
34
+ PCISpecAddressType = ty .Union [ty .Dict [str , str ], str ]
35
+
36
+
32
37
class PciAddressSpec (metaclass = abc .ABCMeta ):
33
38
"""Abstract class for all PCI address spec styles
34
39
35
40
This class checks the address fields of the pci.passthrough_whitelist
36
41
"""
37
42
43
+ def __init__ (self , pci_addr : str ) -> None :
44
+ self .domain = ''
45
+ self .bus = ''
46
+ self .slot = ''
47
+ self .func = ''
48
+
38
49
@abc .abstractmethod
39
50
def match (self , pci_addr ):
40
51
pass
41
52
42
- def is_single_address (self ):
53
+ def is_single_address (self ) -> bool :
43
54
return all ([
44
55
all (c in string .hexdigits for c in self .domain ),
45
56
all (c in string .hexdigits for c in self .bus ),
46
57
all (c in string .hexdigits for c in self .slot ),
47
58
all (c in string .hexdigits for c in self .func )])
48
59
49
- def _set_pci_dev_info (self , prop , maxval , hex_value ):
60
+ def _set_pci_dev_info (
61
+ self , prop : str , maxval : int , hex_value : str
62
+ ) -> None :
50
63
a = getattr (self , prop )
51
64
if a == ANY :
52
65
return
@@ -70,8 +83,10 @@ class PhysicalPciAddress(PciAddressSpec):
70
83
This function class will validate the address fields for a single
71
84
PCI device.
72
85
"""
73
- def __init__ (self , pci_addr ):
86
+
87
+ def __init__ (self , pci_addr : PCISpecAddressType ) -> None :
74
88
try :
89
+ # TODO(stephenfin): Is this ever actually a string?
75
90
if isinstance (pci_addr , dict ):
76
91
self .domain = pci_addr ['domain' ]
77
92
self .bus = pci_addr ['bus' ]
@@ -87,7 +102,7 @@ def __init__(self, pci_addr):
87
102
except (KeyError , ValueError ):
88
103
raise exception .PciDeviceWrongAddressFormat (address = pci_addr )
89
104
90
- def match (self , phys_pci_addr ) :
105
+ def match (self , phys_pci_addr : PciAddressSpec ) -> bool :
91
106
conditions = [
92
107
self .domain == phys_pci_addr .domain ,
93
108
self .bus == phys_pci_addr .bus ,
@@ -104,7 +119,7 @@ class PciAddressGlobSpec(PciAddressSpec):
104
119
check for wildcards, and insert wildcards where the field is left blank.
105
120
"""
106
121
107
- def __init__ (self , pci_addr ) :
122
+ def __init__ (self , pci_addr : str ) -> None :
108
123
self .domain = ANY
109
124
self .bus = ANY
110
125
self .slot = ANY
@@ -129,7 +144,7 @@ def __init__(self, pci_addr):
129
144
self ._set_pci_dev_info ('bus' , MAX_BUS , '%02x' )
130
145
self ._set_pci_dev_info ('slot' , MAX_SLOT , '%02x' )
131
146
132
- def match (self , phys_pci_addr ) :
147
+ def match (self , phys_pci_addr : PciAddressSpec ) -> bool :
133
148
conditions = [
134
149
self .domain in (ANY , phys_pci_addr .domain ),
135
150
self .bus in (ANY , phys_pci_addr .bus ),
@@ -146,7 +161,8 @@ class PciAddressRegexSpec(PciAddressSpec):
146
161
The validation includes check for all PCI address attributes and validate
147
162
their regex.
148
163
"""
149
- def __init__ (self , pci_addr ):
164
+
165
+ def __init__ (self , pci_addr : dict ) -> None :
150
166
try :
151
167
self .domain = pci_addr .get ('domain' , REGEX_ANY )
152
168
self .bus = pci_addr .get ('bus' , REGEX_ANY )
@@ -159,7 +175,7 @@ def __init__(self, pci_addr):
159
175
except re .error :
160
176
raise exception .PciDeviceWrongAddressFormat (address = pci_addr )
161
177
162
- def match (self , phys_pci_addr ) :
178
+ def match (self , phys_pci_addr : PciAddressSpec ) -> bool :
163
179
conditions = [
164
180
bool (self .domain_regex .match (phys_pci_addr .domain )),
165
181
bool (self .bus_regex .match (phys_pci_addr .bus )),
@@ -187,11 +203,13 @@ class WhitelistPciAddress(object):
187
203
| passthrough_whitelist = {"vendor_id":"1137","product_id":"0071"}
188
204
189
205
"""
190
- def __init__ (self , pci_addr , is_physical_function ):
206
+ def __init__ (
207
+ self , pci_addr : PCISpecAddressType , is_physical_function : bool
208
+ ) -> None :
191
209
self .is_physical_function = is_physical_function
192
210
self ._init_address_fields (pci_addr )
193
211
194
- def _check_physical_function (self ):
212
+ def _check_physical_function (self ) -> None :
195
213
if self .pci_address_spec .is_single_address ():
196
214
self .is_physical_function = (
197
215
utils .is_physical_function (
@@ -200,7 +218,8 @@ def _check_physical_function(self):
200
218
self .pci_address_spec .slot ,
201
219
self .pci_address_spec .func ))
202
220
203
- def _init_address_fields (self , pci_addr ):
221
+ def _init_address_fields (self , pci_addr : PCISpecAddressType ) -> None :
222
+ self .pci_address_spec : PciAddressSpec
204
223
if not self .is_physical_function :
205
224
if isinstance (pci_addr , str ):
206
225
self .pci_address_spec = PciAddressGlobSpec (pci_addr )
@@ -212,10 +231,12 @@ def _init_address_fields(self, pci_addr):
212
231
else :
213
232
self .pci_address_spec = PhysicalPciAddress (pci_addr )
214
233
215
- def match (self , pci_addr , pci_phys_addr ):
216
- """Match a device to this PciAddress. Assume this is called given
217
- pci_addr and pci_phys_addr reported by libvirt, no attempt is made to
218
- verify if pci_addr is a VF of pci_phys_addr.
234
+ def match (self , pci_addr : str , pci_phys_addr : ty .Optional [str ]) -> bool :
235
+ """Match a device to this PciAddress.
236
+
237
+ Assume this is called with a ``pci_addr`` and ``pci_phys_addr``
238
+ reported by libvirt. No attempt is made to verify if ``pci_addr`` is a
239
+ VF of ``pci_phys_addr``.
219
240
220
241
:param pci_addr: PCI address of the device to match.
221
242
:param pci_phys_addr: PCI address of the parent of the device to match
@@ -237,51 +258,57 @@ def match(self, pci_addr, pci_phys_addr):
237
258
238
259
239
260
class PciDeviceSpec (PciAddressSpec ):
240
- def __init__ (self , dev_spec ) :
261
+ def __init__ (self , dev_spec : ty . Dict [ str , str ]) -> None :
241
262
self .tags = dev_spec
242
263
self ._init_dev_details ()
243
264
244
- def _init_dev_details (self ):
265
+ def _init_dev_details (self ) -> None :
245
266
self .vendor_id = self .tags .pop ("vendor_id" , ANY )
246
267
self .product_id = self .tags .pop ("product_id" , ANY )
268
+ self .dev_name = self .tags .pop ("devname" , None )
269
+ self .address : ty .Optional [WhitelistPciAddress ] = None
247
270
# Note(moshele): The address attribute can be a string or a dict.
248
271
# For glob syntax or specific pci it is a string and for regex syntax
249
272
# it is a dict. The WhitelistPciAddress class handles both types.
250
- self .address = self .tags .pop ("address" , None )
251
- self .dev_name = self .tags .pop ("devname" , None )
273
+ address = self .tags .pop ("address" , None )
252
274
253
275
self .vendor_id = self .vendor_id .strip ()
254
276
self ._set_pci_dev_info ('vendor_id' , MAX_VENDOR_ID , '%04x' )
255
277
self ._set_pci_dev_info ('product_id' , MAX_PRODUCT_ID , '%04x' )
256
278
257
- if self . address and self .dev_name :
279
+ if address and self .dev_name :
258
280
raise exception .PciDeviceInvalidDeviceName ()
281
+
259
282
if not self .dev_name :
260
- pci_address = self .address or "*:*:*.*"
261
- self .address = WhitelistPciAddress (pci_address , False )
283
+ self .address = WhitelistPciAddress (address or '*:*:*.*' , False )
284
+
285
+ def match (self , dev_dict : ty .Dict [str , str ]) -> bool :
286
+ address_obj : ty .Optional [WhitelistPciAddress ]
262
287
263
- def match (self , dev_dict ):
264
288
if self .dev_name :
265
- address_str , pf = utils .get_function_by_ifname (
266
- self .dev_name )
289
+ address_str , pf = utils .get_function_by_ifname (self .dev_name )
267
290
if not address_str :
268
291
return False
269
292
# Note(moshele): In this case we always passing a string
270
293
# of the PF pci address
271
294
address_obj = WhitelistPciAddress (address_str , pf )
272
- elif self .address :
295
+ else : # use self.address
273
296
address_obj = self .address
297
+
298
+ if not address_obj :
299
+ return False
300
+
274
301
return all ([
275
302
self .vendor_id in (ANY , dev_dict ['vendor_id' ]),
276
303
self .product_id in (ANY , dev_dict ['product_id' ]),
277
304
address_obj .match (dev_dict ['address' ],
278
305
dev_dict .get ('parent_addr' ))])
279
306
280
- def match_pci_obj (self , pci_obj ) :
307
+ def match_pci_obj (self , pci_obj : 'objects.PciDevice' ) -> bool :
281
308
return self .match ({'vendor_id' : pci_obj .vendor_id ,
282
309
'product_id' : pci_obj .product_id ,
283
310
'address' : pci_obj .address ,
284
311
'parent_addr' : pci_obj .parent_addr })
285
312
286
- def get_tags (self ):
313
+ def get_tags (self ) -> ty . Dict [ str , str ] :
287
314
return self .tags
0 commit comments