File: vif.py

package info (click to toggle)
python-os-vif 4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 948 kB
  • sloc: python: 5,503; makefile: 25; sh: 2
file content (609 lines) | stat: -rw-r--r-- 21,668 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from debtcollector import removals

from oslo_utils import versionutils
from oslo_versionedobjects import base
from oslo_versionedobjects import fields

from os_vif.objects import base as osv_base
from os_vif.objects import fields as osv_fields


@base.VersionedObjectRegistry.register
class VIFBase(osv_base.VersionedObject, base.ComparableVersionedObject):
    """Represents a virtual network interface.

    The base VIF defines fields that are common to all types of VIF and
    provides an association to the network the VIF is plugged into. It should
    not be instantiated itself - use a subclass instead.
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Unique identifier of the VIF port.
        'id': fields.UUIDField(),

        #: The guest MAC address.
        'address': fields.MACAddressField(nullable=True),

        #: The network to which the VIF is connected.
        'network': fields.ObjectField('Network', nullable=True),

        #: Name of the registered os_vif plugin.
        'plugin': fields.StringField(),

        #: Whether the VIF is initially online.
        'active': fields.BooleanField(default=True),

        #: Whether the host VIF should be preserved on unplug.
        'preserve_on_delete': fields.BooleanField(default=False),

        #: Whether the network service has provided traffic filtering.
        'has_traffic_filtering': fields.BooleanField(default=False),

        #: The virtual port profile metadata.
        'port_profile': fields.ObjectField('VIFPortProfileBase',
                                           subclasses=True)
    }


@base.VersionedObjectRegistry.register
class VIFGeneric(VIFBase):
    """A generic-style VIF.

    Generic-style VIFs are unbound, floating TUN/TAP devices that should be
    setup by the plugin, not the hypervisor. The way the TAP device is
    connected to the host network stack is explicitly left undefined.

    For libvirt drivers, this maps to type="ethernet" which just implies a bare
    TAP device with all setup delegated to the plugin.
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Name of the device to create.
        'vif_name': fields.StringField()
    }


@base.VersionedObjectRegistry.register
class VIFBridge(VIFBase):
    """A bridge-style VIF.

    Bridge-style VIFs are bound to a Linux host bridge by the hypervisor. This
    provides Ethernet layer bridging, typically to the LAN. Other devices may
    be bound to the same L2 virtual bridge.

    For libvirt drivers, this maps to type='bridge'.
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Name of the virtual device to create.
        'vif_name': fields.StringField(),

        #: Name of the physical device to connect to (e.g. ``br0``).
        'bridge_name': fields.StringField(),
    }


@base.VersionedObjectRegistry.register
class VIFOpenVSwitch(VIFBase):
    """A bridge-style VIF specifically for use with OVS.

    Open vSwitch VIFs are bound directly (or indirectly) to an Open vSwitch
    bridge by the hypervisor. Other devices may be bound to the same virtual
    bridge.

    For libvirt drivers, this also maps to type='bridge'.
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Name of the virtual device to create.
        'vif_name': fields.StringField(),

        #: Name of the physical device to connect to (e.g. ``br0``).
        'bridge_name': fields.StringField(),
    }


@base.VersionedObjectRegistry.register
class VIFDirect(VIFBase):
    """A direct-style VIF.

    Despite the confusing name, direct-style VIFs utilize macvtap which is a
    device driver that inserts a software layer between a guest and an SR-IOV
    Virtual Function (VF). Contrast this with
    :class:`~os_vif.objects.vif.VIFHostDevice`, which allows the guest to
    directly connect to the VF.

    The connection to the device may operate in one of a number of different
    modes, :term:`VEPA` (either :term:`802.1Qbg` or :term:`802.1Qbh`),
    passthrough (exclusive assignment of the host NIC) or bridge (ethernet
    layer bridging of traffic). The passthrough mode would be used when there
    is a network device which needs to have a MAC address or VLAN
    configuration. For passthrough of network devices without MAC/VLAN
    configuration, :class:`~os_vif.objects.vif.VIFHostDevice` should be used
    instead.

    For libvirt drivers, this maps to type='direct'
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Name of the device to create.
        'vif_name': fields.StringField(),

        #: The PCI address of the host device.
        'dev_address': fields.PCIAddressField(),

        #: Port connection mode.
        'mode': osv_fields.VIFDirectModeField(),

        #: The VLAN device name to use.
        'vlan_name': fields.StringField(),
    }


@base.VersionedObjectRegistry.register
class VIFVHostUser(VIFBase):
    """A vhostuser-style VIF.

    vhostuser-style VIFs utilize a :term:`userspace vhost <vhost-user>`
    backend, which allows traffic to traverse between the guest and a host
    userspace application (commonly a virtual switch), bypassing the kernel
    network stack. Contrast this with :class:`~os_vif.objects.vif.VIFBridge`,
    where all packets must be handled by the hypervisor.

    For libvirt drivers, this maps to type='vhostuser'
    """

    # Version 1.0: Initial release
    # Version 1.1: Added 'vif_name'
    VERSION = '1.1'

    fields = {
        #: Name of the vhostuser port to create.
        'vif_name': fields.StringField(),

        #: UNIX socket path.
        'path': fields.StringField(),

        #: UNIX socket access permissions.
        'mode': osv_fields.VIFVHostUserModeField(),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1) and 'vif_name' in primitive:
            del primitive['vif_name']
        super(VIFVHostUser, self).obj_make_compatible(primitive, '1.0')


@base.VersionedObjectRegistry.register
class VIFHostDevice(VIFBase):
    """A hostdev-style VIF.

    Hostdev-style VIFs provide a guest with direct access to an :term:`SR-IOV`
    :term:`Virtual Function` (VF) or an entire :term:`Physical Function` (PF).
    Contrast this with :class:`~ovs_vif.objects.vif.VIFDirect`, which includes
    a software layer between the interface and the guest.

    For libvirt drivers, this maps to type='hostdev'
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: The type of the host device.
        #:
        #: Valid values are ``ethernet`` and ``generic``.
        #:
        #: - ``ethernet`` is ``<interface type='hostdev'>``
        #: - ``generic`` is ``<hostdev mode='subsystem' type='pci'>``
        'dev_type': osv_fields.VIFHostDeviceDevTypeField(),

        #: The PCI address of the host device.
        'dev_address': fields.PCIAddressField(),
    }


@base.VersionedObjectRegistry.register
class VIFNestedDPDK(VIFBase):
    """A nested DPDK-style VIF.

    Nested DPDK-style VIFs are used by Kuryr-Kubernetes to provide accelerated
    DPDK datapath for nested Kubernetes pods running inside the VM. The port
    is first attached to the virtual machine, bound to the userspace driver
    (e.g. ``uio_pci_generic``, ``igb_uio`` or ``vfio-pci``) and then consumed
    by Kubernetes pod via the kuryr-kubernetes CNI plugin.

    This does not apply to libvirt drivers.
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: PCI address of the device.
        'pci_address': fields.StringField(),

        #: Name of the driver the device was previously bound to; it makes
        #: the controller driver agnostic (virtio, SR-IOV, etc.).
        'dev_driver': fields.StringField(),
    }


@base.VersionedObjectRegistry.register
class DatapathOffloadBase(osv_base.VersionedObject,
                          base.ComparableVersionedObject):
    """Base class for all types of datapath offload."""

    # Version 1.0: Initial release
    VERSION = '1.0'


@base.VersionedObjectRegistry.register
class DatapathOffloadRepresentor(DatapathOffloadBase):
    """Offload type for VF Representors conforming to the switchdev model.

    This datapath offloads provides the metadata required to associate a VIF
    with a :term:`VF` representor conforming to the `switchdev`_ kernel model.
    If ``representor_name`` is specified, it indicates a desire to rename the
    representor to the given name on plugging.

    .. _switchdev: https://netdevconf.org/1.2/session.html?or-gerlitz
    """

    # Version 1.0: Initial release
    VERSION = '1.0'

    fields = {
        #: Name to set on the representor (if set).
        'representor_name': fields.StringField(nullable=True),

        #: The PCI address of the Virtual Function.
        'representor_address': fields.StringField(nullable=True),
    }


@base.VersionedObjectRegistry.register
class VIFPortProfileBase(osv_base.VersionedObject,
                         base.ComparableVersionedObject):
    """Base class for all types of port profile.

    The base profile defines fields that are common to all types of profile. It
    should not be instantiated itself - use a subclass instead.
    """

    # Version 1.0: Initial release
    # Version 1.1: Added 'datapath_offload'
    VERSION = '1.1'

    fields = {
        #: Datapath offload type of the port.
        'datapath_offload': fields.ObjectField('DatapathOffloadBase',
                                               nullable=True,
                                               subclasses=True),
    }

    obj_relationships = {
        'datapath_offload': (('1.1', '1.0'),),
    }


@base.VersionedObjectRegistry.register
class VIFPortProfileOpenVSwitch(VIFPortProfileBase):
    """Port profile info for Open vSwitch networks.

    This profile provides the metadata required to associate a VIF with an Open
    vSwitch interface.
    """

    # Version 1.0: Initial release
    # Version 1.1: Added 'datapath_type'
    # Version 1.2: VIFPortProfileBase updated to 1.1 from 1.0
    # Version 1.3: Added 'create_port'
    VERSION = '1.3'

    fields = {
        #: A UUID to uniquely identify the interface. If omitted one will be
        #: generated automatically.
        'interface_id': fields.UUIDField(),

        #: The OpenVSwitch port profile for the interface.
        'profile_id': fields.StringField(),

        #: Datapath type of the bridge.
        'datapath_type': fields.StringField(nullable=True),

        #: Whether the os-vif plugin should add the port to the bridge.
        'create_port': fields.BooleanField(default=False),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 3) and 'create_port' in primitive:
            del primitive['create_port']
        if target_version < (1, 1) and 'datapath_type' in primitive:
            del primitive['datapath_type']
        if target_version < (1, 2):
            super(VIFPortProfileOpenVSwitch, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfileOpenVSwitch, self).obj_make_compatible(
                primitive, '1.1')


@base.VersionedObjectRegistry.register
class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch):
    """Port profile info for Open vSwitch networks using fast path.

    This profile provides the metadata required to associate a :term:`fast
    path <Fast Path>` VIF with an :term:`Open vSwitch` port.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
    # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
    # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
    VERSION = '1.3'

    fields = {
        #: Name of the bridge (managed by fast path) to connect to.
        'bridge_name': fields.StringField(),

        #: Whether the OpenVSwitch network is using hybrid plug.
        'hybrid_plug': fields.BooleanField(default=False),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
                primitive, '1.0')
        elif target_version < (1, 2):
            super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
                primitive, '1.1')
        elif target_version < (1, 3):
            super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
                primitive, '1.2')
        else:
            super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
                primitive, '1.3')


@removals.removed_class("VIFPortProfileOVSRepresentor",
                        category=PendingDeprecationWarning)
@base.VersionedObjectRegistry.register
class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch):
    """Port profile info for OpenVSwitch networks using a representor.

    This profile provides the metadata required to associate a VIF with a
    :term:`VF` representor and :term:`Open vSwitch` port. If `representor_name`
    is specified, it indicates a desire to rename the representor to the given
    name on plugging.

    .. note::

        This port profile is provided for backwards compatibility only.

        This interface has been superceded by the one provided by the
        :class:`DatapathOffloadRepresentor` class, which is now a field element
        of the :class:`VIFPortProfileBase` class. The ``datapath_offload``
        field in port profiles should be used instead.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
    # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
    # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
    VERSION = '1.3'

    fields = {
        #: Name to set on the representor (if set).
        'representor_name': fields.StringField(nullable=True),

        #: The PCI address of the Virtual Function.
        'representor_address': fields.PCIAddressField(nullable=True),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
                primitive, '1.0')
        elif target_version < (1, 2):
            super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
                primitive, '1.1')
        elif target_version < (1, 3):
            super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
                primitive, '1.2')
        else:
            super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
                primitive, '1.3')


@base.VersionedObjectRegistry.register
class VIFPortProfileFPBridge(VIFPortProfileBase):
    """Port profile info for Linux Bridge networks using fast path.

    This profile provides the metadata required to associate a :term:`fast
    path <Fast Path>` VIF with a :term:`Linux Bridge` port.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0
    VERSION = '1.1'

    fields = {
        #: Name of the bridge (managed by fast path) to connect to.
        'bridge_name': fields.StringField(),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfileFPBridge, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfileFPBridge, self).obj_make_compatible(
                primitive, '1.1')


@base.VersionedObjectRegistry.register
class VIFPortProfileFPTap(VIFPortProfileBase):
    """Port profile info for Calico networks using fast path.

    This profile provides the metadata required to associate a :term:`fast
    path <Fast Path>` VIF with a :term:`Calico` port.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0
    VERSION = '1.1'

    fields = {
        #: The MAC address of the host vhostuser port.
        'mac_address': fields.MACAddressField(nullable=True),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfileFPTap, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfileFPTap, self).obj_make_compatible(
                primitive, '1.1')


@base.VersionedObjectRegistry.register
class VIFPortProfile8021Qbg(VIFPortProfileBase):
    """Port profile info for VEPA 802.1qbg networks.

    This profile provides the metadata required to associate a VIF with a VEPA
    host device supporting the :term:`802.1Qbg` spec.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0
    VERSION = '1.1'

    fields = {
        # TODO(stephenfin): Apparently the value 0 is reserved for manager_id,
        # so should we set 'minimum=1'?
        # https://libvirt.org/formatdomain.html#elementsNICS

        #: The VSI Manager ID identifies the database containing the VSI type
        #: and instance definitions.
        'manager_id': fields.IntegerField(),

        #: The VSI Type ID identifies a VSI type characterizing the network
        #: access. VSI types are typically managed by network administrator.
        'type_id': fields.IntegerField(),

        #: The VSI Type Version allows multiple versions of a VSI Type.
        'type_id_version': fields.IntegerField(),

        #: The VSI Instance ID Identifier is generated when a VSI instance
        #: (i.e. a virtual interface of a virtual machine) is created. This is
        #: a globally unique identifier.
        'instance_id': fields.UUIDField(),
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfile8021Qbg, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfile8021Qbg, self).obj_make_compatible(
                primitive, '1.1')


@base.VersionedObjectRegistry.register
class VIFPortProfile8021Qbh(VIFPortProfileBase):
    """Port profile info for VEPA 802.1qbh networks.

    This profile provides the metadata required to associate a VIF with a VEPA
    host device supporting the :term:`802.1Qbh` spec.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0
    VERSION = '1.1'

    fields = {
        #: The name of the port profile that is to be applied to this
        #: interface. This name is resolved by the port profile database into
        #: the network parameters from the port profile, and those network
        #: parameters will be applied to this interface.
        'profile_id': fields.StringField()
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfile8021Qbh, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfile8021Qbh, self).obj_make_compatible(
                primitive, '1.1')


@base.VersionedObjectRegistry.register
class VIFPortProfileK8sDPDK(VIFPortProfileBase):
    """Port profile info for Kuryr-Kubernetes DPDK ports.

    This profile provides the metadata required to associate nested DPDK VIF
    with a Kubernetes pod.
    """

    # Version 1.0: Initial release
    # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0
    VERSION = '1.1'

    fields = {
        #: Specify whether this vif requires L3 setup.
        'l3_setup': fields.BooleanField(),

        #: String containing URL representing object in Kubernetes v1 API.
        'selflink': fields.StringField(),

        #: String used in Kubernetes v1 API to identify the server's internal
        #: version of this object.
        'resourceversion': fields.StringField()
    }

    def obj_make_compatible(self, primitive, target_version):
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1):
            super(VIFPortProfileK8sDPDK, self).obj_make_compatible(
                primitive, '1.0')
        else:
            super(VIFPortProfileK8sDPDK, self).obj_make_compatible(
                primitive, '1.1')