os-vif 4.2.1__py3-none-any.whl → 4.3.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.
Potentially problematic release.
This version of os-vif might be problematic. Click here for more details.
- os_vif/internal/ip/ip_command.py +6 -2
- os_vif/internal/ip/linux/impl_pyroute2.py +10 -1
- os_vif/objects/vif.py +25 -5
- os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py +111 -0
- os_vif/tests/unit/internal/ip/linux/test_impl_pyroute2.py +66 -0
- os_vif/tests/unit/test_objects.py +60 -3
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info}/METADATA +12 -2
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info}/RECORD +21 -21
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info}/WHEEL +1 -1
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info/licenses}/AUTHORS +2 -0
- os_vif-4.3.0.dist-info/pbr.json +1 -0
- vif_plug_ovs/exception.py +6 -0
- vif_plug_ovs/linux_net.py +23 -0
- vif_plug_ovs/ovs.py +58 -1
- vif_plug_ovs/tests/functional/ovsdb/test_ovsdb_lib.py +1 -6
- vif_plug_ovs/tests/functional/test_plugin.py +57 -0
- vif_plug_ovs/tests/unit/test_linux_net.py +44 -0
- vif_plug_ovs/tests/unit/test_plugin.py +266 -0
- os_vif-4.2.1.dist-info/pbr.json +0 -1
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info}/entry_points.txt +0 -0
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info/licenses}/LICENSE +0 -0
- {os_vif-4.2.1.dist-info → os_vif-4.3.0.dist-info}/top_level.txt +0 -0
os_vif/internal/ip/ip_command.py
CHANGED
|
@@ -18,6 +18,7 @@ class IpCommand(metaclass=abc.ABCMeta):
|
|
|
18
18
|
TYPE_VETH = 'veth'
|
|
19
19
|
TYPE_VLAN = 'vlan'
|
|
20
20
|
TYPE_BRIDGE = 'bridge'
|
|
21
|
+
TYPE_TUNTAP = 'tuntap'
|
|
21
22
|
|
|
22
23
|
@abc.abstractmethod
|
|
23
24
|
def set(self, device, check_exit_code=None, state=None, mtu=None,
|
|
@@ -37,11 +38,12 @@ class IpCommand(metaclass=abc.ABCMeta):
|
|
|
37
38
|
|
|
38
39
|
@abc.abstractmethod
|
|
39
40
|
def add(self, device, dev_type, check_exit_code=None, peer=None, link=None,
|
|
40
|
-
vlan_id=None, ageing=None):
|
|
41
|
+
vlan_id=None, ageing=None, mode=None, multiqueue=False):
|
|
41
42
|
"""Method to add an interface.
|
|
42
43
|
|
|
43
44
|
:param device: A network device (string)
|
|
44
|
-
:param dev_type: String network device type (TYPE_VETH, TYPE_VLAN
|
|
45
|
+
:param dev_type: String network device type (TYPE_VETH, TYPE_VLAN,
|
|
46
|
+
TYPE_BRIDGE, TYPE_TUNTAP)
|
|
45
47
|
:param check_exit_code: List of integers of allowed execution exit
|
|
46
48
|
codes
|
|
47
49
|
:param peer: String peer name, for veth interfaces
|
|
@@ -50,6 +52,8 @@ class IpCommand(metaclass=abc.ABCMeta):
|
|
|
50
52
|
:param vlan_id: Integer VLAN ID for VLAN devices
|
|
51
53
|
:param ageing: integer value in seconds before learned
|
|
52
54
|
mac addresses are forgotten.
|
|
55
|
+
:param mode: String mode for tuntap devices ('tap' or 'tun')
|
|
56
|
+
:param multiqueue: Boolean to enable multiqueue for tuntap devices
|
|
53
57
|
:return: status of the command execution
|
|
54
58
|
"""
|
|
55
59
|
|
|
@@ -74,7 +74,7 @@ class PyRoute2(ip_command.IpCommand):
|
|
|
74
74
|
return idx[0]
|
|
75
75
|
|
|
76
76
|
def add(self, device, dev_type, check_exit_code=None, peer=None, link=None,
|
|
77
|
-
vlan_id=None, ageing=None):
|
|
77
|
+
vlan_id=None, ageing=None, mode=None, multiqueue=False):
|
|
78
78
|
check_exit_code = check_exit_code or []
|
|
79
79
|
with iproute.IPRoute() as ip:
|
|
80
80
|
args = {'ifname': device,
|
|
@@ -102,6 +102,15 @@ class PyRoute2(ip_command.IpCommand):
|
|
|
102
102
|
# what policy to use and keep this code generic.
|
|
103
103
|
if ageing is not None:
|
|
104
104
|
args['IFLA_BR_AGEING_TIME'] = ageing
|
|
105
|
+
elif self.TYPE_TUNTAP == dev_type:
|
|
106
|
+
# Set mode (default to 'tap' if not specified)
|
|
107
|
+
# This matches the 'ip tuntap add' command behavior
|
|
108
|
+
tap_mode = mode if mode else 'tap'
|
|
109
|
+
args['mode'] = tap_mode
|
|
110
|
+
# Enable multiqueue if requested
|
|
111
|
+
# This sets the IFF_MULTI_QUEUE flag in IFTUN_IFR
|
|
112
|
+
if multiqueue:
|
|
113
|
+
args['multi_queue'] = True
|
|
105
114
|
else:
|
|
106
115
|
raise exception.NetworkInterfaceTypeNotDefined(type=dev_type)
|
|
107
116
|
|
os_vif/objects/vif.py
CHANGED
|
@@ -327,7 +327,8 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase):
|
|
|
327
327
|
# Version 1.1: Added 'datapath_type'
|
|
328
328
|
# Version 1.2: VIFPortProfileBase updated to 1.1 from 1.0
|
|
329
329
|
# Version 1.3: Added 'create_port'
|
|
330
|
-
|
|
330
|
+
# Version 1.4: Added 'create_tap' and 'multiqueue'
|
|
331
|
+
VERSION = '1.4'
|
|
331
332
|
|
|
332
333
|
fields = {
|
|
333
334
|
#: A UUID to uniquely identify the interface. If omitted one will be
|
|
@@ -342,10 +343,21 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase):
|
|
|
342
343
|
|
|
343
344
|
#: Whether the os-vif plugin should add the port to the bridge.
|
|
344
345
|
'create_port': fields.BooleanField(default=False),
|
|
346
|
+
|
|
347
|
+
#: Whether the os-vif plugin should create the TAP device.
|
|
348
|
+
'create_tap': fields.BooleanField(default=False),
|
|
349
|
+
|
|
350
|
+
#: Whether to enable multiqueue on the TAP device.
|
|
351
|
+
'multiqueue': fields.BooleanField(default=False),
|
|
345
352
|
}
|
|
346
353
|
|
|
347
354
|
def obj_make_compatible(self, primitive, target_version):
|
|
348
355
|
target_version = versionutils.convert_version_to_tuple(target_version)
|
|
356
|
+
if target_version < (1, 4):
|
|
357
|
+
if 'create_tap' in primitive:
|
|
358
|
+
del primitive['create_tap']
|
|
359
|
+
if 'multiqueue' in primitive:
|
|
360
|
+
del primitive['multiqueue']
|
|
349
361
|
if target_version < (1, 3) and 'create_port' in primitive:
|
|
350
362
|
del primitive['create_port']
|
|
351
363
|
if target_version < (1, 1) and 'datapath_type' in primitive:
|
|
@@ -370,7 +382,8 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch):
|
|
|
370
382
|
# Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
|
|
371
383
|
# Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
|
|
372
384
|
# Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
|
|
373
|
-
|
|
385
|
+
# Version 1.4: VIFPortProfileOpenVSwitch updated to 1.4 from 1.3
|
|
386
|
+
VERSION = '1.4'
|
|
374
387
|
|
|
375
388
|
fields = {
|
|
376
389
|
#: Name of the bridge (managed by fast path) to connect to.
|
|
@@ -391,9 +404,12 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch):
|
|
|
391
404
|
elif target_version < (1, 3):
|
|
392
405
|
super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
|
|
393
406
|
primitive, '1.2')
|
|
394
|
-
|
|
407
|
+
elif target_version < (1, 4):
|
|
395
408
|
super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
|
|
396
409
|
primitive, '1.3')
|
|
410
|
+
else:
|
|
411
|
+
super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
|
|
412
|
+
primitive, '1.4')
|
|
397
413
|
|
|
398
414
|
|
|
399
415
|
@removals.removed_class("VIFPortProfileOVSRepresentor",
|
|
@@ -421,7 +437,8 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch):
|
|
|
421
437
|
# Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
|
|
422
438
|
# Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
|
|
423
439
|
# Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
|
|
424
|
-
|
|
440
|
+
# Version 1.4: VIFPortProfileOpenVSwitch updated to 1.4 from 1.3
|
|
441
|
+
VERSION = '1.4'
|
|
425
442
|
|
|
426
443
|
fields = {
|
|
427
444
|
#: Name to set on the representor (if set).
|
|
@@ -442,9 +459,12 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch):
|
|
|
442
459
|
elif target_version < (1, 3):
|
|
443
460
|
super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
|
|
444
461
|
primitive, '1.2')
|
|
445
|
-
|
|
462
|
+
elif target_version < (1, 4):
|
|
446
463
|
super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
|
|
447
464
|
primitive, '1.3')
|
|
465
|
+
else:
|
|
466
|
+
super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
|
|
467
|
+
primitive, '1.4')
|
|
448
468
|
|
|
449
469
|
|
|
450
470
|
@base.VersionedObjectRegistry.register
|
|
@@ -81,6 +81,22 @@ class ShellIpCommands(object):
|
|
|
81
81
|
return
|
|
82
82
|
return match.group('state')
|
|
83
83
|
|
|
84
|
+
def is_admin_up(self, device):
|
|
85
|
+
"""Check if device is administratively up (UP flag set).
|
|
86
|
+
|
|
87
|
+
This differs from show_state() which returns the operational state.
|
|
88
|
+
TAP devices without a carrier will have state=DOWN but can still
|
|
89
|
+
be administratively UP (UP in flags like <NO-CARRIER,BROADCAST,UP>).
|
|
90
|
+
"""
|
|
91
|
+
# Flags are in angle brackets on the first line, e.g. <NO-CARRIER,UP>
|
|
92
|
+
first_line = self.show_device(device)[0]
|
|
93
|
+
regex = re.compile(r".*<(?P<flags>[^>]+)>")
|
|
94
|
+
match = regex.match(first_line)
|
|
95
|
+
if match is None:
|
|
96
|
+
return False
|
|
97
|
+
flags = match.group('flags').split(',')
|
|
98
|
+
return 'UP' in flags
|
|
99
|
+
|
|
84
100
|
def show_promisc(self, device):
|
|
85
101
|
regex = re.compile(r".*(PROMISC)")
|
|
86
102
|
match = regex.match(self.show_device(device)[0])
|
|
@@ -263,3 +279,98 @@ class TestIpCommand(ShellIpCommands, base.BaseFunctionalTestCase):
|
|
|
263
279
|
_ip_cmd_set(device, master=bridge)
|
|
264
280
|
path = "/sys/class/net/{}/brif/{}".format(bridge, device)
|
|
265
281
|
self.assertTrue(os.path.exists(path))
|
|
282
|
+
|
|
283
|
+
def test_add_tap(self):
|
|
284
|
+
"""Test creating a tap device."""
|
|
285
|
+
device = "test_tap_1"
|
|
286
|
+
self.addCleanup(self.del_device, device)
|
|
287
|
+
_ip_cmd_add(device, 'tuntap', mode='tap')
|
|
288
|
+
self.assertTrue(self.exist_device(device))
|
|
289
|
+
|
|
290
|
+
# Verify it's a tap device by checking /sys/class/net/<dev>/tun_flags
|
|
291
|
+
tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
|
|
292
|
+
if os.path.exists(tun_flags_path):
|
|
293
|
+
with open(tun_flags_path, 'r') as f:
|
|
294
|
+
flags_hex = f.read().strip()
|
|
295
|
+
flags = int(flags_hex, 16)
|
|
296
|
+
# IFF_TAP = 0x0002
|
|
297
|
+
IFF_TAP = 0x0002
|
|
298
|
+
self.assertTrue(flags & IFF_TAP,
|
|
299
|
+
"TAP flag not set. Flags: {}".format(flags_hex))
|
|
300
|
+
|
|
301
|
+
def test_add_tap_with_multiqueue(self):
|
|
302
|
+
"""Test creating a tap device with multiqueue parameter.
|
|
303
|
+
|
|
304
|
+
Note: The IFF_MULTI_QUEUE flag (0x0100) cannot be set via netlink.
|
|
305
|
+
It is only set when a process opens /dev/net/tun with the
|
|
306
|
+
IFF_MULTI_QUEUE flag in the ioctl. Libvirt sets this when attaching
|
|
307
|
+
to the TAP device. This test verifies that:
|
|
308
|
+
1. The TAP device can be created with multiqueue=True without error
|
|
309
|
+
2. The device is properly created as a TAP device
|
|
310
|
+
"""
|
|
311
|
+
device = "test_tap_mq"
|
|
312
|
+
self.addCleanup(self.del_device, device)
|
|
313
|
+
_ip_cmd_add(device, 'tuntap', mode='tap', multiqueue=True)
|
|
314
|
+
self.assertTrue(self.exist_device(device))
|
|
315
|
+
|
|
316
|
+
# Verify it's a tap device by checking /sys/class/net/<dev>/tun_flags
|
|
317
|
+
tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
|
|
318
|
+
if os.path.exists(tun_flags_path):
|
|
319
|
+
with open(tun_flags_path, 'r') as f:
|
|
320
|
+
flags_hex = f.read().strip()
|
|
321
|
+
flags = int(flags_hex, 16)
|
|
322
|
+
# IFF_TAP = 0x0002 - verify it's a TAP device
|
|
323
|
+
IFF_TAP = 0x0002
|
|
324
|
+
self.assertTrue(
|
|
325
|
+
flags & IFF_TAP,
|
|
326
|
+
"TAP flag not set. Flags: %s" % flags_hex)
|
|
327
|
+
|
|
328
|
+
def test_add_tap_idempotent(self):
|
|
329
|
+
"""Test tap device creation is idempotent with exit code handling."""
|
|
330
|
+
device = "test_tap_idemp"
|
|
331
|
+
self.addCleanup(self.del_device, device)
|
|
332
|
+
|
|
333
|
+
# Create the device
|
|
334
|
+
_ip_cmd_add(device, 'tuntap', mode='tap')
|
|
335
|
+
self.assertTrue(self.exist_device(device))
|
|
336
|
+
|
|
337
|
+
# Try to create again with EEXIST in check_exit_code (17)
|
|
338
|
+
# This should not raise an exception
|
|
339
|
+
_ip_cmd_add(device, 'tuntap', mode='tap', check_exit_code=[0, 17])
|
|
340
|
+
self.assertTrue(self.exist_device(device))
|
|
341
|
+
|
|
342
|
+
def test_add_tun_device(self):
|
|
343
|
+
"""Test creating a tun device (not tap)."""
|
|
344
|
+
device = "test_tun_1"
|
|
345
|
+
self.addCleanup(self.del_device, device)
|
|
346
|
+
_ip_cmd_add(device, 'tuntap', mode='tun')
|
|
347
|
+
self.assertTrue(self.exist_device(device))
|
|
348
|
+
|
|
349
|
+
# Verify it's a tun device
|
|
350
|
+
tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
|
|
351
|
+
if os.path.exists(tun_flags_path):
|
|
352
|
+
with open(tun_flags_path, 'r') as f:
|
|
353
|
+
flags_hex = f.read().strip()
|
|
354
|
+
flags = int(flags_hex, 16)
|
|
355
|
+
# IFF_TUN = 0x0001
|
|
356
|
+
IFF_TUN = 0x0001
|
|
357
|
+
self.assertTrue(flags & IFF_TUN,
|
|
358
|
+
"TUN flag not set. Flags: {}".format(flags_hex))
|
|
359
|
+
|
|
360
|
+
def test_tap_set_properties(self):
|
|
361
|
+
"""Test setting properties on a tap device."""
|
|
362
|
+
device = "test_tap_props"
|
|
363
|
+
mac = "36:a7:e4:f9:01:02"
|
|
364
|
+
self.addCleanup(self.del_device, device)
|
|
365
|
+
|
|
366
|
+
# Create tap device
|
|
367
|
+
_ip_cmd_add(device, 'tuntap', mode='tap')
|
|
368
|
+
self.assertTrue(self.exist_device(device))
|
|
369
|
+
|
|
370
|
+
# Set MAC address and state
|
|
371
|
+
_ip_cmd_set(device, address=mac, state='up')
|
|
372
|
+
# TAP devices without a carrier will show state=DOWN but should be
|
|
373
|
+
# administratively UP (UP flag in interface flags)
|
|
374
|
+
self.assertTrue(self.is_admin_up(device),
|
|
375
|
+
"Device should be administratively UP")
|
|
376
|
+
self.assertEqual(mac, self.show_mac(device))
|
|
@@ -175,3 +175,69 @@ class TestIpCommand(base.TestCase):
|
|
|
175
175
|
|
|
176
176
|
self.assertRaises(ipexc.NetlinkError, self.ip.delete, self.DEVICE,
|
|
177
177
|
check_exit_code=[self.OTHER_ERROR_CODE])
|
|
178
|
+
|
|
179
|
+
def test_add_tap(self):
|
|
180
|
+
"""Test creating a basic tap device."""
|
|
181
|
+
self.ip.add(self.DEVICE, 'tuntap', mode='tap')
|
|
182
|
+
args = {'ifname': self.DEVICE,
|
|
183
|
+
'kind': 'tuntap',
|
|
184
|
+
'mode': 'tap'}
|
|
185
|
+
self.ip_link.assert_called_once_with('add', **args)
|
|
186
|
+
|
|
187
|
+
def test_add_tap_default_mode(self):
|
|
188
|
+
"""Test creating tap device with default mode (should be 'tap')."""
|
|
189
|
+
self.ip.add(self.DEVICE, 'tuntap')
|
|
190
|
+
args = {'ifname': self.DEVICE,
|
|
191
|
+
'kind': 'tuntap',
|
|
192
|
+
'mode': 'tap'}
|
|
193
|
+
self.ip_link.assert_called_once_with('add', **args)
|
|
194
|
+
|
|
195
|
+
def test_add_tap_with_multiqueue(self):
|
|
196
|
+
"""Test creating tap device with multiqueue enabled."""
|
|
197
|
+
self.ip.add(self.DEVICE, 'tuntap', mode='tap', multiqueue=True)
|
|
198
|
+
|
|
199
|
+
# Verify the call includes multiqueue flag
|
|
200
|
+
args = {'ifname': self.DEVICE,
|
|
201
|
+
'kind': 'tuntap',
|
|
202
|
+
'mode': 'tap',
|
|
203
|
+
'multi_queue': True}
|
|
204
|
+
self.ip_link.assert_called_once_with('add', **args)
|
|
205
|
+
|
|
206
|
+
def test_add_tun_device(self):
|
|
207
|
+
"""Test creating a tun device (not tap)."""
|
|
208
|
+
self.ip.add(self.DEVICE, 'tuntap', mode='tun')
|
|
209
|
+
args = {'ifname': self.DEVICE,
|
|
210
|
+
'kind': 'tuntap',
|
|
211
|
+
'mode': 'tun'}
|
|
212
|
+
self.ip_link.assert_called_once_with('add', **args)
|
|
213
|
+
|
|
214
|
+
def test_add_tap_exit_code(self):
|
|
215
|
+
"""Test tap device creation with exit code handling."""
|
|
216
|
+
self.ip_link.side_effect = ipexc.NetlinkError(self.ERROR_CODE,
|
|
217
|
+
msg="Error message")
|
|
218
|
+
|
|
219
|
+
# Should not raise when error code matches
|
|
220
|
+
self.ip.add(self.DEVICE, 'tuntap', mode='tap',
|
|
221
|
+
check_exit_code=[self.ERROR_CODE])
|
|
222
|
+
self.ip_link.assert_called_once()
|
|
223
|
+
|
|
224
|
+
# Should raise when exit code doesn't match
|
|
225
|
+
self.assertRaises(
|
|
226
|
+
ipexc.NetlinkError,
|
|
227
|
+
self.ip.add, self.DEVICE, 'tuntap', mode='tap',
|
|
228
|
+
check_exit_code=[self.OTHER_ERROR_CODE])
|
|
229
|
+
|
|
230
|
+
def test_set_no_multiqueue_parameter(self):
|
|
231
|
+
"""Verify set() no longer accepts multiqueue parameter."""
|
|
232
|
+
with mock.patch.object(
|
|
233
|
+
iproute.IPRoute, 'link_lookup', return_value=[1],
|
|
234
|
+
create=True):
|
|
235
|
+
self.ip_link.return_value = [{'flags': 0}]
|
|
236
|
+
|
|
237
|
+
# Should work without multiqueue
|
|
238
|
+
self.ip.set(self.DEVICE, state=self.UP, mtu=self.MTU,
|
|
239
|
+
address=self.MAC)
|
|
240
|
+
|
|
241
|
+
# Should raise TypeError if multiqueue is passed
|
|
242
|
+
self.assertRaises(TypeError, self.ip.set, self.DEVICE,
|
|
243
|
+
multiqueue=True)
|
|
@@ -40,12 +40,12 @@ object_data = {
|
|
|
40
40
|
'VIFPortProfile8021Qbg': '1.1-b3011621809dca9216b50579ce9d6b19',
|
|
41
41
|
'VIFPortProfile8021Qbh': '1.1-226b61b2e76ba452f7b31530cff80ac9',
|
|
42
42
|
'VIFPortProfileBase': '1.1-4982d1621df12ebd1f3b07948f3d0e5f',
|
|
43
|
-
'VIFPortProfileOpenVSwitch': '1.
|
|
44
|
-
'VIFPortProfileFPOpenVSwitch': '1.
|
|
43
|
+
'VIFPortProfileOpenVSwitch': '1.4-54fb321f2b70c37d392fadc226c889e7',
|
|
44
|
+
'VIFPortProfileFPOpenVSwitch': '1.4-20904c1dcdac0641cabf7b02525973bd',
|
|
45
45
|
'VIFPortProfileFPBridge': '1.1-49f1952bf50bab7a95112c908534751f',
|
|
46
46
|
'VIFPortProfileFPTap': '1.1-fd178229477604dfb65de5ce929488e5',
|
|
47
47
|
'VIFVHostUser': '1.1-1f95b43be1f884f090ca1f4d79adfd35',
|
|
48
|
-
'VIFPortProfileOVSRepresentor': '1.
|
|
48
|
+
'VIFPortProfileOVSRepresentor': '1.4-82b7292ee4cd6f808b724d2f5648932b',
|
|
49
49
|
'VIFNestedDPDK': '1.0-fdbaf6b20afd116529929b21aa7158dc',
|
|
50
50
|
'VIFPortProfileK8sDPDK': '1.1-e2a2abd112b14e0239e76b99d9b252ae',
|
|
51
51
|
'DatapathOffloadBase': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d',
|
|
@@ -78,3 +78,60 @@ class TestObjectVersions(base.TestCase):
|
|
|
78
78
|
self.assertIn('vif_name', primitive)
|
|
79
79
|
vif.obj_make_compatible(primitive, '1.0')
|
|
80
80
|
self.assertNotIn('vif_name', primitive)
|
|
81
|
+
|
|
82
|
+
def test_vif_port_profile_ovs_obj_make_compatible_1_4(self):
|
|
83
|
+
"""Test obj_make_compatible removes create_tap and multiqueue for
|
|
84
|
+
versions < 1.4.
|
|
85
|
+
"""
|
|
86
|
+
profile = objects.vif.VIFPortProfileOpenVSwitch(
|
|
87
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
88
|
+
create_tap=True,
|
|
89
|
+
multiqueue=True)
|
|
90
|
+
primitive = profile.obj_to_primitive()['versioned_object.data']
|
|
91
|
+
self.assertIn('create_tap', primitive)
|
|
92
|
+
self.assertIn('multiqueue', primitive)
|
|
93
|
+
|
|
94
|
+
# For version 1.3, both create_tap and multiqueue should be removed
|
|
95
|
+
profile.obj_make_compatible(primitive, '1.3')
|
|
96
|
+
self.assertNotIn('create_tap', primitive)
|
|
97
|
+
self.assertNotIn('multiqueue', primitive)
|
|
98
|
+
|
|
99
|
+
def test_vif_port_profile_ovs_obj_make_compatible_1_3(self):
|
|
100
|
+
"""Test obj_make_compatible removes create_port for versions < 1.3."""
|
|
101
|
+
profile = objects.vif.VIFPortProfileOpenVSwitch(
|
|
102
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
103
|
+
create_port=True)
|
|
104
|
+
primitive = profile.obj_to_primitive()['versioned_object.data']
|
|
105
|
+
self.assertIn('create_port', primitive)
|
|
106
|
+
|
|
107
|
+
# For version 1.2, create_port should be removed
|
|
108
|
+
profile.obj_make_compatible(primitive, '1.2')
|
|
109
|
+
self.assertNotIn('create_port', primitive)
|
|
110
|
+
|
|
111
|
+
def test_vif_port_profile_ovs_create_tap_multiqueue_fields(self):
|
|
112
|
+
"""Test that create_tap and multiqueue fields can be set."""
|
|
113
|
+
profile = objects.vif.VIFPortProfileOpenVSwitch(
|
|
114
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
115
|
+
create_tap=True,
|
|
116
|
+
multiqueue=True)
|
|
117
|
+
self.assertTrue(profile.create_tap)
|
|
118
|
+
self.assertTrue(profile.multiqueue)
|
|
119
|
+
|
|
120
|
+
# Test explicitly set default values
|
|
121
|
+
profile_default = objects.vif.VIFPortProfileOpenVSwitch(
|
|
122
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
123
|
+
create_tap=False,
|
|
124
|
+
multiqueue=False)
|
|
125
|
+
self.assertFalse(profile_default.create_tap)
|
|
126
|
+
self.assertFalse(profile_default.multiqueue)
|
|
127
|
+
|
|
128
|
+
def test_vif_port_profile_ovs_in_operator(self):
|
|
129
|
+
"""Test that 'in' operator works for checking field existence."""
|
|
130
|
+
profile = objects.vif.VIFPortProfileOpenVSwitch(
|
|
131
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
132
|
+
create_tap=True,
|
|
133
|
+
multiqueue=True)
|
|
134
|
+
self.assertIn('create_tap', profile)
|
|
135
|
+
self.assertIn('multiqueue', profile)
|
|
136
|
+
self.assertIn('interface_id', profile)
|
|
137
|
+
self.assertNotIn('nonexistent_field', profile)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: os_vif
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: A library for plugging and unplugging virtual interfaces in OpenStack.
|
|
5
5
|
Home-page: https://docs.openstack.org/os-vif/latest/
|
|
6
6
|
Author: OpenStack
|
|
@@ -34,6 +34,16 @@ Requires-Dist: ovsdbapp>=0.12.1
|
|
|
34
34
|
Requires-Dist: stevedore>=1.20.0
|
|
35
35
|
Requires-Dist: debtcollector>=1.19.0
|
|
36
36
|
Requires-Dist: pyroute2>=0.5.2; sys_platform != "win32"
|
|
37
|
+
Dynamic: author
|
|
38
|
+
Dynamic: author-email
|
|
39
|
+
Dynamic: classifier
|
|
40
|
+
Dynamic: description
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
Dynamic: provides-extra
|
|
44
|
+
Dynamic: requires-dist
|
|
45
|
+
Dynamic: requires-python
|
|
46
|
+
Dynamic: summary
|
|
37
47
|
|
|
38
48
|
========================
|
|
39
49
|
Team and repository tags
|
|
@@ -8,9 +8,9 @@ os_vif/version.py,sha256=ilQe2xTxPDxlzJYWbq8KdHeashflTfC1OZewgFPKPRI,713
|
|
|
8
8
|
os_vif/internal/__init__.py,sha256=VGE1e9o-7RkuTzNhZl4Wivz1tojriLYypVBObhSZfSk,967
|
|
9
9
|
os_vif/internal/ip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
os_vif/internal/ip/api.py,sha256=BlGJdRe_Yn7P23Dejo7gLK-M6UasY8sKrMCz0FPvx2s,722
|
|
11
|
-
os_vif/internal/ip/ip_command.py,sha256=
|
|
11
|
+
os_vif/internal/ip/ip_command.py,sha256=3xOsIOozcZNza78bsAhGHNJTGHiSH9CZSXqwPLeA1oE,3044
|
|
12
12
|
os_vif/internal/ip/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
os_vif/internal/ip/linux/impl_pyroute2.py,sha256=
|
|
13
|
+
os_vif/internal/ip/linux/impl_pyroute2.py,sha256=ZFJwd5FlHxq_rZmfciRPQSG5KGPZPubPbJU6liTNKGI,6002
|
|
14
14
|
os_vif/objects/__init__.py,sha256=ePMVrOlb8ti6YmpdZ15pOXI1XLeFjHvhBvw35abZRZE,883
|
|
15
15
|
os_vif/objects/base.py,sha256=kI0c1gPDN37RhGuOYg18AA7l98uUfpqs14AS9GfE4oE,1139
|
|
16
16
|
os_vif/objects/fields.py,sha256=i_kVqeCOBfcNKuZiB3gBat-8qJWhLtwEQxsl-k5plgw,1761
|
|
@@ -20,7 +20,7 @@ os_vif/objects/instance_info.py,sha256=pdZcq6ZJzT1vFnkeUV_jlCvMNz53QlHRvY-bB1u5n
|
|
|
20
20
|
os_vif/objects/network.py,sha256=L6Ngq_u4vbF_xUc9o2aUW2oq0OWALjXFgB1uHsLaZm4,2134
|
|
21
21
|
os_vif/objects/route.py,sha256=44EbxorPn3QiKusaAoksrYolSR6jCYS7sh5tplHenOE,1352
|
|
22
22
|
os_vif/objects/subnet.py,sha256=ZSiwVUZGZT_kmYuND4PwpN98nImvpwMc-ne5DO-Lkg0,1458
|
|
23
|
-
os_vif/objects/vif.py,sha256=
|
|
23
|
+
os_vif/objects/vif.py,sha256=DlRuvv0ruI246YtvxZG9oP_1pWC50GhzNszZVysPl20,22606
|
|
24
24
|
os_vif/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
os_vif/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
os_vif/tests/functional/base.py,sha256=m2uqvH9BkBcCYU7PtlnBYUmwmQLUiuwVS99scJjYQ04,5005
|
|
@@ -28,20 +28,22 @@ os_vif/tests/functional/privsep.py,sha256=c7dqBiO4d-hxgCq-DgbP2A7HB6fdhZK4X0ADYU
|
|
|
28
28
|
os_vif/tests/functional/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
os_vif/tests/functional/internal/command/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
os_vif/tests/functional/internal/command/ip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py,sha256=
|
|
31
|
+
os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py,sha256=hQrZAnV3S6sbp_6QCS4WHmZIZl-udrw0J8c9VCStqZw,14778
|
|
32
32
|
os_vif/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
os_vif/tests/unit/base.py,sha256=sEjrOSy3yW16WwOorv164ZuUyvKh2TY0gMoVf6lg3kA,795
|
|
34
34
|
os_vif/tests/unit/test_base.py,sha256=iqgweFRWprY98mkGL3HIbV9D8DuX_tUPH8uRiDflwDc,3137
|
|
35
35
|
os_vif/tests/unit/test_exception.py,sha256=UDVJSR3CKU3rc5kmN14ilL9Fj0cgnwQbGoP4weo2P4w,1335
|
|
36
36
|
os_vif/tests/unit/test_host_info.py,sha256=2PYHg4pY-YwUuSg9MyDKJbJhKVGRT6ujJATkzzIPx18,7576
|
|
37
|
-
os_vif/tests/unit/test_objects.py,sha256=
|
|
37
|
+
os_vif/tests/unit/test_objects.py,sha256=Bpd-edRlIZ7ojvNw4V9SaMQd9ih7lSlrKnHDG8Zb9Ns,6292
|
|
38
38
|
os_vif/tests/unit/test_os_vif.py,sha256=b0h65Wa9tvxw-e7c707SoJQjfGzEALSFZUPkTtr_GkY,6612
|
|
39
39
|
os_vif/tests/unit/test_vif.py,sha256=mhg2PZ3iVEPzffO5I0VT1wIUP3c-h7MAqrZgCuZdjxE,18000
|
|
40
40
|
os_vif/tests/unit/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
os_vif/tests/unit/internal/ip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
os_vif/tests/unit/internal/ip/test_api.py,sha256=LnkAM0M8giNjAw_Q4-oRic3WIW3OWq-SCGlde9SCenY,820
|
|
43
43
|
os_vif/tests/unit/internal/ip/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
os_vif/tests/unit/internal/ip/linux/test_impl_pyroute2.py,sha256=
|
|
44
|
+
os_vif/tests/unit/internal/ip/linux/test_impl_pyroute2.py,sha256=9R2YhJlN-DSTYUnR9xLuuN1NlXkwkC1LL0wXnR7b6ck,10207
|
|
45
|
+
os_vif-4.3.0.dist-info/licenses/AUTHORS,sha256=1vx_YLfQyRK6hjRsylsaEcnk3tHr-EeOH2G6htWR224,3434
|
|
46
|
+
os_vif-4.3.0.dist-info/licenses/LICENSE,sha256=XfKg2H1sVi8OoRxoisUlMqoo10TKvHmU_wU39ks7MyA,10143
|
|
45
47
|
vif_plug_linux_bridge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
48
|
vif_plug_linux_bridge/constants.py,sha256=NC8n4uOMFCYrhq0sM1ZeGBKo-Gs4OMR60cYP47wMRCk,602
|
|
47
49
|
vif_plug_linux_bridge/iptables.py,sha256=q4LmAMMzg-r9IgDNTu3jCLjNDM8b0JbGo-qmiA2B-JE,20641
|
|
@@ -59,9 +61,9 @@ vif_plug_noop/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
59
61
|
vif_plug_noop/tests/unit/test_plugin.py,sha256=x8m9zuGtHsPoZRZP6Q6BREAFx0wiEagFtTFlB_i_Bxc,1236
|
|
60
62
|
vif_plug_ovs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
63
|
vif_plug_ovs/constants.py,sha256=vQKnYSeBMjV2RGQPGxk96D8FtgpvJIZEX_yZzUlsGg8,892
|
|
62
|
-
vif_plug_ovs/exception.py,sha256=
|
|
63
|
-
vif_plug_ovs/linux_net.py,sha256=
|
|
64
|
-
vif_plug_ovs/ovs.py,sha256=
|
|
64
|
+
vif_plug_ovs/exception.py,sha256=5MQZsoUFZ7kShXQA3Jeax9CcOYpT2I3h-F8ugNMncks,1569
|
|
65
|
+
vif_plug_ovs/linux_net.py,sha256=El3C-9utimXonEE51D5lDthP5gmFkH_XI6jyrcWXOF4,14873
|
|
66
|
+
vif_plug_ovs/ovs.py,sha256=_j3iCYnvwNemyR_vfAH3xMkWCCvbEWesRA6vrvi-uRE,25386
|
|
65
67
|
vif_plug_ovs/privsep.py,sha256=nPQUkYgjbSjaHMuu40fZArRnf8RBiR73l4YpDF1K1yQ,1100
|
|
66
68
|
vif_plug_ovs/ovsdb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
69
|
vif_plug_ovs/ovsdb/api.py,sha256=_jHR8xokDAPI8sw3IEWuT3hObJuskqVzeVMDaWRbIq0,1293
|
|
@@ -71,19 +73,17 @@ vif_plug_ovs/ovsdb/ovsdb_lib.py,sha256=U7mZk_1q5tnHgWsgBotIqt_-fu7I3pfBGapchmlLc
|
|
|
71
73
|
vif_plug_ovs/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
74
|
vif_plug_ovs/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
75
|
vif_plug_ovs/tests/functional/base.py,sha256=GZKyA9UR9BaEgZ0tv6xyMTQnz9FpKedV2do1ePMB-rw,2059
|
|
74
|
-
vif_plug_ovs/tests/functional/test_plugin.py,sha256=
|
|
76
|
+
vif_plug_ovs/tests/functional/test_plugin.py,sha256=f2XdYkZPiOL5hzzXCM3bMwGw8CMsbjWkA_HvcIFyZZk,13018
|
|
75
77
|
vif_plug_ovs/tests/functional/ovsdb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
-
vif_plug_ovs/tests/functional/ovsdb/test_ovsdb_lib.py,sha256=
|
|
78
|
+
vif_plug_ovs/tests/functional/ovsdb/test_ovsdb_lib.py,sha256=dSmQyqzFn9VSgxEeHr5EHePnhfx_SvlA5IxX1gGGAes,13517
|
|
77
79
|
vif_plug_ovs/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
-
vif_plug_ovs/tests/unit/test_linux_net.py,sha256=
|
|
79
|
-
vif_plug_ovs/tests/unit/test_plugin.py,sha256=
|
|
80
|
+
vif_plug_ovs/tests/unit/test_linux_net.py,sha256=TQ4If-mNl2Q8-JoIrNH8QRPO2jQDTkKlSvwKawsgsSs,19703
|
|
81
|
+
vif_plug_ovs/tests/unit/test_plugin.py,sha256=3tH3jpazI83m9TQaScQ-o9NHSO1_2Fk29LHV9Q_kT4M,43506
|
|
80
82
|
vif_plug_ovs/tests/unit/ovsdb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
81
83
|
vif_plug_ovs/tests/unit/ovsdb/test_ovsdb_lib.py,sha256=mec9WESL92MQZonDVyBrsJJveMcLyvHKPj1GU8yYGjo,10687
|
|
82
|
-
os_vif-4.
|
|
83
|
-
os_vif-4.
|
|
84
|
-
os_vif-4.
|
|
85
|
-
os_vif-4.
|
|
86
|
-
os_vif-4.
|
|
87
|
-
os_vif-4.
|
|
88
|
-
os_vif-4.2.1.dist-info/top_level.txt,sha256=ULBxtkTk3bkfzCSYJjifWehfjJdMODVzC6SX5l_CNKo,56
|
|
89
|
-
os_vif-4.2.1.dist-info/RECORD,,
|
|
84
|
+
os_vif-4.3.0.dist-info/METADATA,sha256=9GHnBKuER01IWkhNAktrSm96MNkjK6-K8RxXoFMLw9g,2533
|
|
85
|
+
os_vif-4.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
86
|
+
os_vif-4.3.0.dist-info/entry_points.txt,sha256=BU9WplZnF_bjwT4SQP5n1mKu2f0R5xXBOznXP1GygHM,206
|
|
87
|
+
os_vif-4.3.0.dist-info/pbr.json,sha256=5Ah5X1ihi7jQlwKHCYVuLIcFpYUEB-NSbfUFgmYOH2o,46
|
|
88
|
+
os_vif-4.3.0.dist-info/top_level.txt,sha256=ULBxtkTk3bkfzCSYJjifWehfjJdMODVzC6SX5l_CNKo,56
|
|
89
|
+
os_vif-4.3.0.dist-info/RECORD,,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
Adrian Chiris <adrianc@mellanox.com>
|
|
2
|
+
Adrien Cunin <a.cunin@syseleven.de>
|
|
2
3
|
Alin Balutoiu <abalutoiu@cloudbasesolutions.com>
|
|
3
4
|
Andreas Jaeger <aj@suse.com>
|
|
4
5
|
Balazs Gibizer <gibi@redhat.com>
|
|
5
6
|
Bence Romsics <bence.romsics@gmail.com>
|
|
7
|
+
Bodo Petermann <b.petermann@syseleven.de>
|
|
6
8
|
Brian Haley <brian.haley@hpe.com>
|
|
7
9
|
Cao Xuan Hoang <hoangcx@vn.fujitsu.com>
|
|
8
10
|
Carlos Goncalves <cgoncalves@redhat.com>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"git_version": "8cbe6ee", "is_release": true}
|
vif_plug_ovs/exception.py
CHANGED
|
@@ -35,3 +35,9 @@ class RepresentorNotFound(osv_exception.ExceptionBase):
|
|
|
35
35
|
|
|
36
36
|
class PciDeviceNotFoundById(osv_exception.ExceptionBase):
|
|
37
37
|
msg_fmt = _("PCI device %(id)s not found")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TapCreationNotSupported(osv_exception.ExceptionBase):
|
|
41
|
+
msg_fmt = _('Tap device creation requested for unsupported VIF type. '
|
|
42
|
+
'create_tap is only supported for VIFOpenVSwitch, got '
|
|
43
|
+
'%(vif_type)s')
|
vif_plug_ovs/linux_net.py
CHANGED
|
@@ -90,6 +90,29 @@ def update_veth_pair(dev1_name, dev2_name, mtu):
|
|
|
90
90
|
_update_device_mtu(dev, mtu)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
@privsep.vif_plug.entrypoint
|
|
94
|
+
def create_tap(dev, mtu, mac, multiqueue=False):
|
|
95
|
+
"""Create a tap device with the specified configuration.
|
|
96
|
+
|
|
97
|
+
Creates a tap device using pyroute2's netlink interface, with optional
|
|
98
|
+
multiqueue support for better performance with multiple VCPUs.
|
|
99
|
+
|
|
100
|
+
:param dev: Device name (string)
|
|
101
|
+
:param mtu: MTU value (integer)
|
|
102
|
+
:param mac: MAC address (string)
|
|
103
|
+
:param multiqueue: Enable multiqueue support (boolean, default False)
|
|
104
|
+
Requires Linux kernel 3.8+
|
|
105
|
+
"""
|
|
106
|
+
# Create the tap device with optional multiqueue support
|
|
107
|
+
# Use check_exit_code=[0, 17] to handle EEXIST (device already exists)
|
|
108
|
+
ip_lib.add(dev, 'tuntap', mode='tap', multiqueue=multiqueue,
|
|
109
|
+
check_exit_code=[0, 17])
|
|
110
|
+
# Configure the device state and MAC address
|
|
111
|
+
ip_lib.set(dev, state='up', address=mac, check_exit_code=[0, 2, 254])
|
|
112
|
+
# Set MTU if specified
|
|
113
|
+
_update_device_mtu(dev, mtu)
|
|
114
|
+
|
|
115
|
+
|
|
93
116
|
def _disable_ipv6(bridge):
|
|
94
117
|
"""Disable ipv6 if available for bridge. Must be called from
|
|
95
118
|
privsep context.
|
vif_plug_ovs/ovs.py
CHANGED
|
@@ -223,7 +223,7 @@ class OvsPlugin(plugin.PluginBase):
|
|
|
223
223
|
# This is a mitigation for the performance regression
|
|
224
224
|
# introduced by the fix for bug #1734320. See bug #2017868
|
|
225
225
|
# for more details.
|
|
226
|
-
if not self.ovsdb.port_exists(vif_name,
|
|
226
|
+
if not self.ovsdb.port_exists(vif_name, bridge):
|
|
227
227
|
kwargs['qos_type'] = qos_type
|
|
228
228
|
self.ovsdb.create_ovs_vif_port(
|
|
229
229
|
bridge,
|
|
@@ -232,11 +232,62 @@ class OvsPlugin(plugin.PluginBase):
|
|
|
232
232
|
vif.address, instance_info.uuid,
|
|
233
233
|
mtu=mtu,
|
|
234
234
|
**kwargs)
|
|
235
|
+
# Check if tap creation is requested:
|
|
236
|
+
# - 'field in profile.fields' checks if field exists in schema
|
|
237
|
+
# - 'field in profile' checks if the attribute is set on instance
|
|
238
|
+
profile = vif.port_profile
|
|
239
|
+
create_tap = (
|
|
240
|
+
isinstance(profile, objects.vif.VIFPortProfileOpenVSwitch) and
|
|
241
|
+
'create_tap' in profile.fields and
|
|
242
|
+
'create_tap' in profile and
|
|
243
|
+
profile.create_tap
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if create_tap:
|
|
247
|
+
# Validate VIF type - only VIFOpenVSwitch supports tap creation
|
|
248
|
+
if not isinstance(vif, objects.vif.VIFOpenVSwitch):
|
|
249
|
+
raise exception.TapCreationNotSupported(
|
|
250
|
+
vif_type=vif.__class__.__name__)
|
|
251
|
+
|
|
252
|
+
# Get multiqueue setting from port profile if available
|
|
253
|
+
# 'field in profile.fields' checks schema, 'field in profile'
|
|
254
|
+
# checks if the attribute is set
|
|
255
|
+
multiqueue = ('multiqueue' in profile.fields and
|
|
256
|
+
'multiqueue' in profile and
|
|
257
|
+
profile.multiqueue)
|
|
258
|
+
|
|
259
|
+
# Create the tap device with proper MAC and MTU if it doesn't
|
|
260
|
+
# already exist (e.g., from a previous plug during init_host)
|
|
261
|
+
if not ip_lib.exists(vif_name):
|
|
262
|
+
linux_net.create_tap(
|
|
263
|
+
vif_name, mtu, vif.address, multiqueue=multiqueue)
|
|
235
264
|
|
|
236
265
|
def _update_vif_port(self, vif, vif_name):
|
|
237
266
|
mtu = self._get_mtu(vif)
|
|
238
267
|
self.ovsdb.update_ovs_vif_port(vif_name, mtu)
|
|
239
268
|
|
|
269
|
+
def _delete_tap_if_required(self, vif, vif_name):
|
|
270
|
+
"""Delete tap device if it was created via create_tap flag.
|
|
271
|
+
|
|
272
|
+
:param vif: VIF object
|
|
273
|
+
:param vif_name: Name of the tap device
|
|
274
|
+
"""
|
|
275
|
+
# Check if this VIF had a tap device created for it:
|
|
276
|
+
# - 'field in profile.fields' checks if field exists in schema
|
|
277
|
+
# - 'field in profile' checks if the attribute is set on instance
|
|
278
|
+
profile = getattr(vif, 'port_profile', None)
|
|
279
|
+
create_tap = (
|
|
280
|
+
profile is not None and
|
|
281
|
+
isinstance(profile, objects.vif.VIFPortProfileOpenVSwitch) and
|
|
282
|
+
isinstance(vif, objects.vif.VIFOpenVSwitch) and
|
|
283
|
+
'create_tap' in profile.fields and
|
|
284
|
+
'create_tap' in profile and
|
|
285
|
+
profile.create_tap
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if create_tap and ip_lib.exists(vif_name):
|
|
289
|
+
linux_net.delete_net_dev(vif_name)
|
|
290
|
+
|
|
240
291
|
@staticmethod
|
|
241
292
|
def _get_vif_datapath_type(vif, datapath=constants.OVS_DATAPATH_SYSTEM):
|
|
242
293
|
profile = vif.port_profile
|
|
@@ -428,6 +479,9 @@ class OvsPlugin(plugin.PluginBase):
|
|
|
428
479
|
|
|
429
480
|
def _unplug_port_bridge(self, vif, instance_info):
|
|
430
481
|
"""Create a per-VIF OVS bridge and patch pair."""
|
|
482
|
+
# Delete tap device if it was created
|
|
483
|
+
self._delete_tap_if_required(vif, vif.vif_name)
|
|
484
|
+
|
|
431
485
|
# NOTE(sean-k-mooney): the port name prefix should not be
|
|
432
486
|
# changed to avoid loosing ports on upgrade.
|
|
433
487
|
port_bridge_name = self.gen_port_name('pb', vif.id)
|
|
@@ -444,6 +498,9 @@ class OvsPlugin(plugin.PluginBase):
|
|
|
444
498
|
|
|
445
499
|
def _unplug_vif_generic(self, vif, instance_info):
|
|
446
500
|
"""Remove port from OVS."""
|
|
501
|
+
# Delete tap device if it was created
|
|
502
|
+
self._delete_tap_if_required(vif, vif.vif_name)
|
|
503
|
+
|
|
447
504
|
# NOTE(sean-k-mooney): even with the partial revert of change
|
|
448
505
|
# Iaf15fa7a678ec2624f7c12f634269c465fbad930 this should be correct
|
|
449
506
|
# so this is not removed.
|
|
@@ -183,12 +183,7 @@ class TestOVSDBLib(testscenarios.WithScenarios,
|
|
|
183
183
|
'Interface', port_bridge_port, 'options', port_opts)
|
|
184
184
|
|
|
185
185
|
def test_create_ovs_vif_port_with_default_qos(self):
|
|
186
|
-
|
|
187
|
-
self.skipTest(
|
|
188
|
-
'test_create_ovs_vif_port_with_default_qos is unstable '
|
|
189
|
-
'when run with the native driver, see: '
|
|
190
|
-
'https://bugs.launchpad.net/os-vif/+bug/2087982')
|
|
191
|
-
port_name = 'qos-port-' + self.interface
|
|
186
|
+
port_name = 'def-qos-port-' + self.interface
|
|
192
187
|
iface_id = 'iface_id'
|
|
193
188
|
mac = 'ca:fe:ca:fe:ca:fe'
|
|
194
189
|
instance_id = uuidutils.generate_uuid()
|
|
@@ -186,6 +186,63 @@ class TestOVSPlugin(testscenarios.WithScenarios,
|
|
|
186
186
|
'QoS', str(qos_uuid), 'type', None
|
|
187
187
|
)
|
|
188
188
|
|
|
189
|
+
def test_plug_unplug_ovs_port_with_qos_per_port_bridge(self):
|
|
190
|
+
with mock.patch.object(self.plugin.config, 'per_port_bridge', True):
|
|
191
|
+
bridge = 'br-ppb-' + self.interface
|
|
192
|
+
vif_name = 'port-ppb-' + self.interface
|
|
193
|
+
qos_type = CONF.os_vif_ovs.default_qos_type
|
|
194
|
+
|
|
195
|
+
network = objects.network.Network(
|
|
196
|
+
id='6977aa43-b7c3-484a-8bcb-09d77374981b',
|
|
197
|
+
bridge=bridge,
|
|
198
|
+
subnets=self.subnets,
|
|
199
|
+
vlan=99)
|
|
200
|
+
vif = objects.vif.VIFOpenVSwitch(
|
|
201
|
+
id='e5cf7112-a72f-43a4-aaa3-48a5cfbdeaca',
|
|
202
|
+
address='ca:fe:de:ad:be:ef',
|
|
203
|
+
network=network,
|
|
204
|
+
port_profile=self.profile_ovs_system,
|
|
205
|
+
vif_name=vif_name)
|
|
206
|
+
port_bridge_name = self.plugin.gen_port_name('pb', vif.id)
|
|
207
|
+
|
|
208
|
+
self.addCleanup(self._del_bridge, bridge)
|
|
209
|
+
self.addCleanup(self._del_bridge, port_bridge_name)
|
|
210
|
+
self.addCleanup(
|
|
211
|
+
self.ovs.delete_ovs_vif_port, port_bridge_name, vif_name,
|
|
212
|
+
delete_netdev=False, qos_type=qos_type
|
|
213
|
+
)
|
|
214
|
+
self.addCleanup(del_device, vif_name)
|
|
215
|
+
add_device(vif_name, 'dummy')
|
|
216
|
+
# plugging a vif will create the port and bridges
|
|
217
|
+
# if they don't exist
|
|
218
|
+
self.plugin.plug(vif, self.instance)
|
|
219
|
+
self.assertTrue(self._check_bridge(bridge))
|
|
220
|
+
self.assertTrue(self._check_bridge(port_bridge_name))
|
|
221
|
+
self.assertTrue(self._check_port(vif_name, port_bridge_name))
|
|
222
|
+
|
|
223
|
+
# Plugging a second time should succeed
|
|
224
|
+
self.plugin.plug(vif, self.instance)
|
|
225
|
+
|
|
226
|
+
# Check that the 2nd plug did not create a 2nd qos row,
|
|
227
|
+
# which happened in https://bugs.launchpad.net/os-vif/+bug/2133225
|
|
228
|
+
qos = self.ovs.get_qos(vif_name, qos_type)
|
|
229
|
+
self.assertEqual(1, len(qos))
|
|
230
|
+
|
|
231
|
+
qos_uuid = qos[0]['_uuid']
|
|
232
|
+
self._check_parameter('Port', vif_name, 'qos', qos_uuid)
|
|
233
|
+
self._check_parameter(
|
|
234
|
+
'QoS', str(qos_uuid), 'type', qos_type
|
|
235
|
+
)
|
|
236
|
+
# unplugging a port will not delete the int bridge,
|
|
237
|
+
# only the per-port bridge.
|
|
238
|
+
self.plugin.unplug(vif, self.instance)
|
|
239
|
+
self.assertTrue(self._check_bridge(bridge))
|
|
240
|
+
self.assertFalse(self._check_bridge(port_bridge_name))
|
|
241
|
+
self.assertFalse(self._check_port(vif_name, bridge))
|
|
242
|
+
self._check_parameter(
|
|
243
|
+
'QoS', str(qos_uuid), 'type', None
|
|
244
|
+
)
|
|
245
|
+
|
|
189
246
|
def test_plug_br_int_isolate_vif_dead_vlan(self):
|
|
190
247
|
with mock.patch.object(self.plugin.config, 'isolate_vif', True):
|
|
191
248
|
network = objects.network.Network(
|
|
@@ -396,3 +396,47 @@ class LinuxNetTest(testtools.TestCase):
|
|
|
396
396
|
mock_isfile.return_value = False
|
|
397
397
|
phys_port_name = linux_net._get_phys_switch_id("ifname")
|
|
398
398
|
self.assertIsNone(phys_port_name)
|
|
399
|
+
|
|
400
|
+
@mock.patch.object(linux_net, "_update_device_mtu")
|
|
401
|
+
@mock.patch.object(ip_lib, "set")
|
|
402
|
+
@mock.patch.object(ip_lib, "add")
|
|
403
|
+
def test_create_tap(self, mock_add, mock_set, mock_update_mtu):
|
|
404
|
+
"""Test basic tap device creation."""
|
|
405
|
+
linux_net.create_tap("tap0", 1500, "aa:bb:cc:dd:ee:ff",
|
|
406
|
+
multiqueue=False)
|
|
407
|
+
|
|
408
|
+
mock_add.assert_called_once_with("tap0", "tuntap", mode="tap",
|
|
409
|
+
multiqueue=False,
|
|
410
|
+
check_exit_code=[0, 17])
|
|
411
|
+
mock_set.assert_called_once_with("tap0", state="up",
|
|
412
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
413
|
+
check_exit_code=[0, 2, 254])
|
|
414
|
+
mock_update_mtu.assert_called_once_with("tap0", 1500)
|
|
415
|
+
|
|
416
|
+
@mock.patch.object(linux_net, "_update_device_mtu")
|
|
417
|
+
@mock.patch.object(ip_lib, "set")
|
|
418
|
+
@mock.patch.object(ip_lib, "add")
|
|
419
|
+
def test_create_tap_with_multiqueue(self, mock_add, mock_set,
|
|
420
|
+
mock_update_mtu):
|
|
421
|
+
"""Test tap device creation with multiqueue enabled."""
|
|
422
|
+
linux_net.create_tap("tap0", 1500, "aa:bb:cc:dd:ee:ff",
|
|
423
|
+
multiqueue=True)
|
|
424
|
+
|
|
425
|
+
mock_add.assert_called_once_with("tap0", "tuntap", mode="tap",
|
|
426
|
+
multiqueue=True,
|
|
427
|
+
check_exit_code=[0, 17])
|
|
428
|
+
mock_set.assert_called_once_with("tap0", state="up",
|
|
429
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
430
|
+
check_exit_code=[0, 2, 254])
|
|
431
|
+
mock_update_mtu.assert_called_once_with("tap0", 1500)
|
|
432
|
+
|
|
433
|
+
@mock.patch.object(linux_net, "_update_device_mtu")
|
|
434
|
+
@mock.patch.object(ip_lib, "set")
|
|
435
|
+
@mock.patch.object(ip_lib, "add")
|
|
436
|
+
def test_create_tap_no_mtu(self, mock_add, mock_set, mock_update_mtu):
|
|
437
|
+
"""Test tap device creation without MTU."""
|
|
438
|
+
linux_net.create_tap("tap0", None, "aa:bb:cc:dd:ee:ff")
|
|
439
|
+
|
|
440
|
+
mock_add.assert_called_once()
|
|
441
|
+
mock_set.assert_called_once()
|
|
442
|
+
mock_update_mtu.assert_called_once_with("tap0", None)
|
|
@@ -19,6 +19,7 @@ from os_vif import objects
|
|
|
19
19
|
from os_vif.objects import fields
|
|
20
20
|
|
|
21
21
|
from vif_plug_ovs import constants
|
|
22
|
+
from vif_plug_ovs import exception
|
|
22
23
|
from vif_plug_ovs import linux_net
|
|
23
24
|
from vif_plug_ovs import ovs
|
|
24
25
|
from vif_plug_ovs.ovsdb import ovsdb_lib
|
|
@@ -96,6 +97,13 @@ class PluginTest(testtools.TestCase):
|
|
|
96
97
|
vif_name='tap-xxx-yyy-zzz',
|
|
97
98
|
port_profile=self.profile_ovs)
|
|
98
99
|
|
|
100
|
+
self.vif_ovs_system = objects.vif.VIFOpenVSwitch(
|
|
101
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
102
|
+
address='ca:fe:de:ad:be:ef',
|
|
103
|
+
network=self.network_ovs,
|
|
104
|
+
vif_name='tap-xxx-yyy-zzz',
|
|
105
|
+
port_profile=self.profile_ovs_system)
|
|
106
|
+
|
|
99
107
|
# This is used for ironic with vif_type=smartnic
|
|
100
108
|
self.vif_ovs_smart_nic = objects.vif.VIFOpenVSwitch(
|
|
101
109
|
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
@@ -241,6 +249,88 @@ class PluginTest(testtools.TestCase):
|
|
|
241
249
|
mtu=plugin.config.network_device_mtu,
|
|
242
250
|
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
|
243
251
|
|
|
252
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
253
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
254
|
+
def test_create_vif_port_qos_port_bridge_true_port_new(
|
|
255
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
256
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
257
|
+
mock_port_exists.return_value = False
|
|
258
|
+
port_bridge_name = "port-bridge-xxx"
|
|
259
|
+
# _create_vif_port as from _plug_port_bridge
|
|
260
|
+
plugin._create_vif_port(
|
|
261
|
+
self.vif_ovs_system, mock.sentinel.vif_name, self.instance,
|
|
262
|
+
bridge=port_bridge_name, set_ids=False)
|
|
263
|
+
# port existence should be checked on the per-port bridge
|
|
264
|
+
mock_port_exists.assert_called_once_with(
|
|
265
|
+
mock.sentinel.vif_name, port_bridge_name)
|
|
266
|
+
# qos_type should be set for the new port
|
|
267
|
+
mock_create_ovs_vif_port.assert_called_once_with(
|
|
268
|
+
port_bridge_name, mock.sentinel.vif_name,
|
|
269
|
+
self.vif_ovs_system.port_profile.interface_id,
|
|
270
|
+
self.vif_ovs_system.address, self.instance.uuid,
|
|
271
|
+
mtu=plugin.config.network_device_mtu,
|
|
272
|
+
set_ids=False,
|
|
273
|
+
qos_type="linux-noop")
|
|
274
|
+
|
|
275
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
276
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
277
|
+
def test_create_vif_port_qos_port_bridge_true_port_exists(
|
|
278
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
279
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
280
|
+
mock_port_exists.return_value = True
|
|
281
|
+
port_bridge_name = "port-bridge-xxx"
|
|
282
|
+
# _create_vif_port as from _plug_port_bridge
|
|
283
|
+
plugin._create_vif_port(
|
|
284
|
+
self.vif_ovs_system, mock.sentinel.vif_name, self.instance,
|
|
285
|
+
bridge=port_bridge_name, set_ids=False)
|
|
286
|
+
# port existence should be checked on the per-port bridge
|
|
287
|
+
mock_port_exists.assert_called_once_with(
|
|
288
|
+
mock.sentinel.vif_name, port_bridge_name)
|
|
289
|
+
# qos_type should not be set for the existing port
|
|
290
|
+
mock_create_ovs_vif_port.assert_called_once_with(
|
|
291
|
+
port_bridge_name, mock.sentinel.vif_name,
|
|
292
|
+
self.vif_ovs_system.port_profile.interface_id,
|
|
293
|
+
self.vif_ovs_system.address, self.instance.uuid,
|
|
294
|
+
mtu=plugin.config.network_device_mtu,
|
|
295
|
+
set_ids=False)
|
|
296
|
+
|
|
297
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
298
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
299
|
+
def test_create_vif_port_qos_port_bridge_false_port_new(
|
|
300
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
301
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
302
|
+
mock_port_exists.return_value = False
|
|
303
|
+
# _create_vif_port as from _plug_vif_generic
|
|
304
|
+
plugin._create_vif_port(
|
|
305
|
+
self.vif_ovs_system, mock.sentinel.vif_name, self.instance)
|
|
306
|
+
mock_port_exists.assert_called_once_with(
|
|
307
|
+
mock.sentinel.vif_name, self.vif_ovs_system.network.bridge)
|
|
308
|
+
# qos_type should be set for the new port
|
|
309
|
+
mock_create_ovs_vif_port.assert_called_once_with(
|
|
310
|
+
self.vif_ovs_system.network.bridge, mock.sentinel.vif_name,
|
|
311
|
+
self.vif_ovs_system.port_profile.interface_id,
|
|
312
|
+
self.vif_ovs_system.address, self.instance.uuid,
|
|
313
|
+
mtu=plugin.config.network_device_mtu,
|
|
314
|
+
qos_type="linux-noop")
|
|
315
|
+
|
|
316
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
317
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
318
|
+
def test_create_vif_port_qos_port_bridge_false_port_exists(
|
|
319
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
320
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
321
|
+
mock_port_exists.return_value = True
|
|
322
|
+
# _create_vif_port as from _plug_vif_generic
|
|
323
|
+
plugin._create_vif_port(
|
|
324
|
+
self.vif_ovs_system, mock.sentinel.vif_name, self.instance)
|
|
325
|
+
mock_port_exists.assert_called_once_with(
|
|
326
|
+
mock.sentinel.vif_name, self.vif_ovs_system.network.bridge)
|
|
327
|
+
# qos_type should not be set for the existing port
|
|
328
|
+
mock_create_ovs_vif_port.assert_called_once_with(
|
|
329
|
+
self.vif_ovs_system.network.bridge, mock.sentinel.vif_name,
|
|
330
|
+
self.vif_ovs_system.port_profile.interface_id,
|
|
331
|
+
self.vif_ovs_system.address, self.instance.uuid,
|
|
332
|
+
mtu=plugin.config.network_device_mtu)
|
|
333
|
+
|
|
244
334
|
@mock.patch.object(ovs.OvsPlugin, '_plug_vif_generic')
|
|
245
335
|
def test_plug_ovs_port_bridge_false(self, plug_vif_generic):
|
|
246
336
|
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
@@ -648,3 +738,179 @@ class PluginTest(testtools.TestCase):
|
|
|
648
738
|
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
649
739
|
plugin.unplug(self.vif_ovs, self.instance)
|
|
650
740
|
m_unplug_generic.assert_called_once()
|
|
741
|
+
|
|
742
|
+
@mock.patch.object(linux_net, 'create_tap')
|
|
743
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
744
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
745
|
+
def test_create_vif_port_with_tap_creation(
|
|
746
|
+
self, mock_port_exists, mock_create_ovs_vif_port, mock_create_tap):
|
|
747
|
+
"""Test that create_tap is called when create_tap flag is set."""
|
|
748
|
+
# Create a profile with create_tap=True
|
|
749
|
+
profile_with_tap = objects.vif.VIFPortProfileOpenVSwitch(
|
|
750
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
751
|
+
create_tap=True)
|
|
752
|
+
vif_with_tap = objects.vif.VIFOpenVSwitch(
|
|
753
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
754
|
+
address='ca:fe:de:ad:be:ef',
|
|
755
|
+
network=self.network_ovs,
|
|
756
|
+
vif_name='tap-xxx-yyy-zzz',
|
|
757
|
+
port_profile=profile_with_tap)
|
|
758
|
+
|
|
759
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
760
|
+
mock_port_exists.return_value = False
|
|
761
|
+
plugin._create_vif_port(
|
|
762
|
+
vif_with_tap, 'tap-xxx-yyy-zzz', self.instance)
|
|
763
|
+
|
|
764
|
+
# Verify create_tap was called with correct parameters
|
|
765
|
+
mock_create_tap.assert_called_once_with(
|
|
766
|
+
'tap-xxx-yyy-zzz',
|
|
767
|
+
plugin.config.network_device_mtu,
|
|
768
|
+
'ca:fe:de:ad:be:ef',
|
|
769
|
+
multiqueue=False)
|
|
770
|
+
|
|
771
|
+
@mock.patch.object(linux_net, 'create_tap')
|
|
772
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
773
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
774
|
+
def test_create_vif_port_with_tap_and_multiqueue(
|
|
775
|
+
self, mock_port_exists, mock_create_ovs_vif_port, mock_create_tap):
|
|
776
|
+
"""Test that create_tap is called with multiqueue when both are set."""
|
|
777
|
+
# Create a profile with create_tap=True and multiqueue=True
|
|
778
|
+
profile_with_tap_mq = objects.vif.VIFPortProfileOpenVSwitch(
|
|
779
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
780
|
+
create_tap=True,
|
|
781
|
+
multiqueue=True)
|
|
782
|
+
vif_with_tap_mq = objects.vif.VIFOpenVSwitch(
|
|
783
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
784
|
+
address='ca:fe:de:ad:be:ef',
|
|
785
|
+
network=self.network_ovs,
|
|
786
|
+
vif_name='tap-xxx-yyy-zzz',
|
|
787
|
+
port_profile=profile_with_tap_mq)
|
|
788
|
+
|
|
789
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
790
|
+
mock_port_exists.return_value = False
|
|
791
|
+
plugin._create_vif_port(
|
|
792
|
+
vif_with_tap_mq, 'tap-xxx-yyy-zzz', self.instance)
|
|
793
|
+
|
|
794
|
+
# Verify create_tap was called with multiqueue=True
|
|
795
|
+
mock_create_tap.assert_called_once_with(
|
|
796
|
+
'tap-xxx-yyy-zzz',
|
|
797
|
+
plugin.config.network_device_mtu,
|
|
798
|
+
'ca:fe:de:ad:be:ef',
|
|
799
|
+
multiqueue=True)
|
|
800
|
+
|
|
801
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
802
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
803
|
+
def test_create_vif_port_tap_not_supported_vhostuser(
|
|
804
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
805
|
+
"""Test that TapCreationNotSupported is raised for VIFVHostUser."""
|
|
806
|
+
# Create a VIFVHostUser with create_tap=True
|
|
807
|
+
profile_with_tap = objects.vif.VIFPortProfileOpenVSwitch(
|
|
808
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
809
|
+
create_tap=True)
|
|
810
|
+
vif_vhostuser_with_tap = objects.vif.VIFVHostUser(
|
|
811
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
812
|
+
address='ca:fe:de:ad:be:ef',
|
|
813
|
+
network=self.network_ovs,
|
|
814
|
+
path='/var/run/openvswitch/vhub679325f-ca',
|
|
815
|
+
mode='client',
|
|
816
|
+
port_profile=profile_with_tap)
|
|
817
|
+
|
|
818
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
819
|
+
mock_port_exists.return_value = False
|
|
820
|
+
|
|
821
|
+
# Verify exception is raised
|
|
822
|
+
self.assertRaises(
|
|
823
|
+
exception.TapCreationNotSupported,
|
|
824
|
+
plugin._create_vif_port,
|
|
825
|
+
vif_vhostuser_with_tap, 'vhub679325f-ca', self.instance)
|
|
826
|
+
|
|
827
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
|
828
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'port_exists')
|
|
829
|
+
def test_create_vif_port_tap_not_supported_hostdevice(
|
|
830
|
+
self, mock_port_exists, mock_create_ovs_vif_port):
|
|
831
|
+
"""Test that TapCreationNotSupported is raised for VIFHostDevice."""
|
|
832
|
+
# Create a VIFHostDevice with create_tap=True
|
|
833
|
+
profile_with_tap = objects.vif.VIFPortProfileOpenVSwitch(
|
|
834
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
835
|
+
create_tap=True)
|
|
836
|
+
vif_hostdevice_with_tap = objects.vif.VIFHostDevice(
|
|
837
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
838
|
+
address='ca:fe:de:ad:be:ef',
|
|
839
|
+
network=self.network_ovs,
|
|
840
|
+
dev_type=fields.VIFHostDeviceDevType.ETHERNET,
|
|
841
|
+
dev_address='0002:24:12.3',
|
|
842
|
+
port_profile=profile_with_tap)
|
|
843
|
+
|
|
844
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
845
|
+
mock_port_exists.return_value = False
|
|
846
|
+
|
|
847
|
+
# Verify exception is raised
|
|
848
|
+
self.assertRaises(
|
|
849
|
+
exception.TapCreationNotSupported,
|
|
850
|
+
plugin._create_vif_port,
|
|
851
|
+
vif_hostdevice_with_tap, 'tap-xxx-yyy-zzz', self.instance)
|
|
852
|
+
|
|
853
|
+
@mock.patch.object(ip_lib, 'exists', return_value=True)
|
|
854
|
+
@mock.patch.object(linux_net, 'delete_net_dev')
|
|
855
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'delete_ovs_vif_port')
|
|
856
|
+
def test_unplug_vif_generic_deletes_tap(
|
|
857
|
+
self, mock_delete_ovs_vif_port, mock_delete_net_dev,
|
|
858
|
+
mock_exists):
|
|
859
|
+
"""Test that tap device is deleted when unplugging with
|
|
860
|
+
create_tap=True.
|
|
861
|
+
"""
|
|
862
|
+
# Create a VIF with create_tap=True
|
|
863
|
+
profile_with_tap = objects.vif.VIFPortProfileOpenVSwitch(
|
|
864
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
865
|
+
create_tap=True)
|
|
866
|
+
vif_with_tap = objects.vif.VIFOpenVSwitch(
|
|
867
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
868
|
+
address='ca:fe:de:ad:be:ef',
|
|
869
|
+
network=self.network_ovs,
|
|
870
|
+
vif_name='tap-xxx-yyy-zzz',
|
|
871
|
+
port_profile=profile_with_tap)
|
|
872
|
+
|
|
873
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
874
|
+
plugin._unplug_vif_generic(vif_with_tap, self.instance)
|
|
875
|
+
|
|
876
|
+
# Verify delete_net_dev was called with vif_name
|
|
877
|
+
mock_delete_net_dev.assert_called_once_with('tap-xxx-yyy-zzz')
|
|
878
|
+
|
|
879
|
+
@mock.patch.object(linux_net, 'delete_net_dev')
|
|
880
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'delete_ovs_vif_port')
|
|
881
|
+
def test_unplug_vif_generic_no_tap_deletion_when_not_created(
|
|
882
|
+
self, mock_delete_ovs_vif_port, mock_delete_net_dev):
|
|
883
|
+
"""Test that tap device is not deleted when create_tap=False."""
|
|
884
|
+
# Use default vif_ovs which has create_tap=False (or unset)
|
|
885
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
886
|
+
plugin._unplug_vif_generic(self.vif_ovs, self.instance)
|
|
887
|
+
|
|
888
|
+
# Verify delete_net_dev was not called
|
|
889
|
+
mock_delete_net_dev.assert_not_called()
|
|
890
|
+
|
|
891
|
+
@mock.patch.object(ip_lib, 'exists', return_value=True)
|
|
892
|
+
@mock.patch.object(linux_net, 'delete_net_dev')
|
|
893
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'delete_ovs_vif_port')
|
|
894
|
+
@mock.patch.object(ovsdb_lib.BaseOVS, 'delete_ovs_bridge')
|
|
895
|
+
def test_unplug_port_bridge_deletes_tap(
|
|
896
|
+
self, mock_delete_ovs_bridge, mock_delete_ovs_vif_port,
|
|
897
|
+
mock_delete_net_dev, mock_exists):
|
|
898
|
+
"""Test that tap device is deleted when unplugging port bridge with
|
|
899
|
+
create_tap=True.
|
|
900
|
+
"""
|
|
901
|
+
# Create a VIF with create_tap=True
|
|
902
|
+
profile_with_tap = objects.vif.VIFPortProfileOpenVSwitch(
|
|
903
|
+
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
904
|
+
create_tap=True)
|
|
905
|
+
vif_with_tap = objects.vif.VIFOpenVSwitch(
|
|
906
|
+
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
907
|
+
address='ca:fe:de:ad:be:ef',
|
|
908
|
+
network=self.network_ovs,
|
|
909
|
+
vif_name='tap-xxx-yyy-zzz',
|
|
910
|
+
port_profile=profile_with_tap)
|
|
911
|
+
|
|
912
|
+
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
913
|
+
plugin._unplug_port_bridge(vif_with_tap, self.instance)
|
|
914
|
+
|
|
915
|
+
# Verify delete_net_dev was called with vif_name
|
|
916
|
+
mock_delete_net_dev.assert_called_once_with('tap-xxx-yyy-zzz')
|
os_vif-4.2.1.dist-info/pbr.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"git_version": "b33415b", "is_release": true}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|