1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13from debtcollector import removals 14 15from oslo_utils import versionutils 16from oslo_versionedobjects import base 17from oslo_versionedobjects import fields 18 19from os_vif.objects import base as osv_base 20from os_vif.objects import fields as osv_fields 21 22 23@base.VersionedObjectRegistry.register 24class VIFBase(osv_base.VersionedObject, base.ComparableVersionedObject): 25 """Represents a virtual network interface. 26 27 The base VIF defines fields that are common to all types of VIF and 28 provides an association to the network the VIF is plugged into. It should 29 not be instantiated itself - use a subclass instead. 30 """ 31 32 # Version 1.0: Initial release 33 VERSION = '1.0' 34 35 fields = { 36 #: Unique identifier of the VIF port. 37 'id': fields.UUIDField(), 38 39 #: The guest MAC address. 40 'address': fields.MACAddressField(nullable=True), 41 42 #: The network to which the VIF is connected. 43 'network': fields.ObjectField('Network', nullable=True), 44 45 #: Name of the registered os_vif plugin. 46 'plugin': fields.StringField(), 47 48 #: Whether the VIF is initially online. 49 'active': fields.BooleanField(default=True), 50 51 #: Whether the host VIF should be preserved on unplug. 52 'preserve_on_delete': fields.BooleanField(default=False), 53 54 #: Whether the network service has provided traffic filtering. 55 'has_traffic_filtering': fields.BooleanField(default=False), 56 57 #: The virtual port profile metadata. 58 'port_profile': fields.ObjectField('VIFPortProfileBase', 59 subclasses=True) 60 } 61 62 63@base.VersionedObjectRegistry.register 64class VIFGeneric(VIFBase): 65 """A generic-style VIF. 66 67 Generic-style VIFs are unbound, floating TUN/TAP devices that should be 68 setup by the plugin, not the hypervisor. The way the TAP device is 69 connected to the host network stack is explicitly left undefined. 70 71 For libvirt drivers, this maps to type="ethernet" which just implies a bare 72 TAP device with all setup delegated to the plugin. 73 """ 74 75 # Version 1.0: Initial release 76 VERSION = '1.0' 77 78 fields = { 79 #: Name of the device to create. 80 'vif_name': fields.StringField() 81 } 82 83 84@base.VersionedObjectRegistry.register 85class VIFBridge(VIFBase): 86 """A bridge-style VIF. 87 88 Bridge-style VIFs are bound to a Linux host bridge by the hypervisor. This 89 provides Ethernet layer bridging, typically to the LAN. Other devices may 90 be bound to the same L2 virtual bridge. 91 92 For libvirt drivers, this maps to type='bridge'. 93 """ 94 95 # Version 1.0: Initial release 96 VERSION = '1.0' 97 98 fields = { 99 #: Name of the virtual device to create. 100 'vif_name': fields.StringField(), 101 102 #: Name of the physical device to connect to (e.g. ``br0``). 103 'bridge_name': fields.StringField(), 104 } 105 106 107@base.VersionedObjectRegistry.register 108class VIFOpenVSwitch(VIFBase): 109 """A bridge-style VIF specifically for use with OVS. 110 111 Open vSwitch VIFs are bound directly (or indirectly) to an Open vSwitch 112 bridge by the hypervisor. Other devices may be bound to the same virtual 113 bridge. 114 115 For libvirt drivers, this also maps to type='bridge'. 116 """ 117 118 # Version 1.0: Initial release 119 VERSION = '1.0' 120 121 fields = { 122 #: Name of the virtual device to create. 123 'vif_name': fields.StringField(), 124 125 #: Name of the physical device to connect to (e.g. ``br0``). 126 'bridge_name': fields.StringField(), 127 } 128 129 130@base.VersionedObjectRegistry.register 131class VIFDirect(VIFBase): 132 """A direct-style VIF. 133 134 Despite the confusing name, direct-style VIFs utilize macvtap which is a 135 device driver that inserts a software layer between a guest and an SR-IOV 136 Virtual Function (VF). Contrast this with 137 :class:`~os_vif.objects.vif.VIFHostDevice`, which allows the guest to 138 directly connect to the VF. 139 140 The connection to the device may operate in one of a number of different 141 modes, :term:`VEPA` (either :term:`802.1Qbg` or :term:`802.1Qbh`), 142 passthrough (exclusive assignment of the host NIC) or bridge (ethernet 143 layer bridging of traffic). The passthrough mode would be used when there 144 is a network device which needs to have a MAC address or VLAN 145 configuration. For passthrough of network devices without MAC/VLAN 146 configuration, :class:`~os_vif.objects.vif.VIFHostDevice` should be used 147 instead. 148 149 For libvirt drivers, this maps to type='direct' 150 """ 151 152 # Version 1.0: Initial release 153 VERSION = '1.0' 154 155 fields = { 156 #: Name of the device to create. 157 'vif_name': fields.StringField(), 158 159 #: The PCI address of the host device. 160 'dev_address': fields.PCIAddressField(), 161 162 #: Port connection mode. 163 'mode': osv_fields.VIFDirectModeField(), 164 165 #: The VLAN device name to use. 166 'vlan_name': fields.StringField(), 167 } 168 169 170@base.VersionedObjectRegistry.register 171class VIFVHostUser(VIFBase): 172 """A vhostuser-style VIF. 173 174 vhostuser-style VIFs utilize a :term:`userspace vhost <vhost-user>` 175 backend, which allows traffic to traverse between the guest and a host 176 userspace application (commonly a virtual switch), bypassing the kernel 177 network stack. Contrast this with :class:`~os_vif.objects.vif.VIFBridge`, 178 where all packets must be handled by the hypervisor. 179 180 For libvirt drivers, this maps to type='vhostuser' 181 """ 182 183 # Version 1.0: Initial release 184 # Version 1.1: Added 'vif_name' 185 VERSION = '1.1' 186 187 fields = { 188 #: Name of the vhostuser port to create. 189 'vif_name': fields.StringField(), 190 191 #: UNIX socket path. 192 'path': fields.StringField(), 193 194 #: UNIX socket access permissions. 195 'mode': osv_fields.VIFVHostUserModeField(), 196 } 197 198 def obj_make_compatible(self, primitive, target_version): 199 target_version = versionutils.convert_version_to_tuple(target_version) 200 if target_version < (1, 1) and 'vif_name' in primitive: 201 del primitive['vif_name'] 202 super(VIFVHostUser, self).obj_make_compatible(primitive, '1.0') 203 204 205@base.VersionedObjectRegistry.register 206class VIFHostDevice(VIFBase): 207 """A hostdev-style VIF. 208 209 Hostdev-style VIFs provide a guest with direct access to an :term:`SR-IOV` 210 :term:`Virtual Function` (VF) or an entire :term:`Physical Function` (PF). 211 Contrast this with :class:`~ovs_vif.objects.vif.VIFDirect`, which includes 212 a software layer between the interface and the guest. 213 214 For libvirt drivers, this maps to type='hostdev' 215 """ 216 217 # Version 1.0: Initial release 218 VERSION = '1.0' 219 220 fields = { 221 #: The type of the host device. 222 #: 223 #: Valid values are ``ethernet`` and ``generic``. 224 #: 225 #: - ``ethernet`` is ``<interface type='hostdev'>`` 226 #: - ``generic`` is ``<hostdev mode='subsystem' type='pci'>`` 227 'dev_type': osv_fields.VIFHostDeviceDevTypeField(), 228 229 #: The PCI address of the host device. 230 'dev_address': fields.PCIAddressField(), 231 } 232 233 234@base.VersionedObjectRegistry.register 235class VIFNestedDPDK(VIFBase): 236 """A nested DPDK-style VIF. 237 238 Nested DPDK-style VIFs are used by Kuryr-Kubernetes to provide accelerated 239 DPDK datapath for nested Kubernetes pods running inside the VM. The port 240 is first attached to the virtual machine, bound to the userspace driver 241 (e.g. ``uio_pci_generic``, ``igb_uio`` or ``vfio-pci``) and then consumed 242 by Kubernetes pod via the kuryr-kubernetes CNI plugin. 243 244 This does not apply to libvirt drivers. 245 """ 246 247 # Version 1.0: Initial release 248 VERSION = '1.0' 249 250 fields = { 251 #: PCI address of the device. 252 'pci_address': fields.StringField(), 253 254 #: Name of the driver the device was previously bound to; it makes 255 #: the controller driver agnostic (virtio, SR-IOV, etc.). 256 'dev_driver': fields.StringField(), 257 } 258 259 260@base.VersionedObjectRegistry.register 261class DatapathOffloadBase(osv_base.VersionedObject, 262 base.ComparableVersionedObject): 263 """Base class for all types of datapath offload.""" 264 265 # Version 1.0: Initial release 266 VERSION = '1.0' 267 268 269@base.VersionedObjectRegistry.register 270class DatapathOffloadRepresentor(DatapathOffloadBase): 271 """Offload type for VF Representors conforming to the switchdev model. 272 273 This datapath offloads provides the metadata required to associate a VIF 274 with a :term:`VF` representor conforming to the `switchdev`_ kernel model. 275 If ``representor_name`` is specified, it indicates a desire to rename the 276 representor to the given name on plugging. 277 278 .. _switchdev: https://netdevconf.org/1.2/session.html?or-gerlitz 279 """ 280 281 # Version 1.0: Initial release 282 VERSION = '1.0' 283 284 fields = { 285 #: Name to set on the representor (if set). 286 'representor_name': fields.StringField(nullable=True), 287 288 #: The PCI address of the Virtual Function. 289 'representor_address': fields.StringField(nullable=True), 290 } 291 292 293@base.VersionedObjectRegistry.register 294class VIFPortProfileBase(osv_base.VersionedObject, 295 base.ComparableVersionedObject): 296 """Base class for all types of port profile. 297 298 The base profile defines fields that are common to all types of profile. It 299 should not be instantiated itself - use a subclass instead. 300 """ 301 302 # Version 1.0: Initial release 303 # Version 1.1: Added 'datapath_offload' 304 VERSION = '1.1' 305 306 fields = { 307 #: Datapath offload type of the port. 308 'datapath_offload': fields.ObjectField('DatapathOffloadBase', 309 nullable=True, 310 subclasses=True), 311 } 312 313 obj_relationships = { 314 'datapath_offload': (('1.1', '1.0'),), 315 } 316 317 318@base.VersionedObjectRegistry.register 319class VIFPortProfileOpenVSwitch(VIFPortProfileBase): 320 """Port profile info for Open vSwitch networks. 321 322 This profile provides the metadata required to associate a VIF with an Open 323 vSwitch interface. 324 """ 325 326 # Version 1.0: Initial release 327 # Version 1.1: Added 'datapath_type' 328 # Version 1.2: VIFPortProfileBase updated to 1.1 from 1.0 329 # Version 1.3: Added 'create_port' 330 VERSION = '1.3' 331 332 fields = { 333 #: A UUID to uniquely identify the interface. If omitted one will be 334 #: generated automatically. 335 'interface_id': fields.UUIDField(), 336 337 #: The OpenVSwitch port profile for the interface. 338 'profile_id': fields.StringField(), 339 340 #: Datapath type of the bridge. 341 'datapath_type': fields.StringField(nullable=True), 342 343 #: Whether the os-vif plugin should add the port to the bridge. 344 'create_port': fields.BooleanField(default=False), 345 } 346 347 def obj_make_compatible(self, primitive, target_version): 348 target_version = versionutils.convert_version_to_tuple(target_version) 349 if target_version < (1, 3) and 'create_port' in primitive: 350 del primitive['create_port'] 351 if target_version < (1, 1) and 'datapath_type' in primitive: 352 del primitive['datapath_type'] 353 if target_version < (1, 2): 354 super(VIFPortProfileOpenVSwitch, self).obj_make_compatible( 355 primitive, '1.0') 356 else: 357 super(VIFPortProfileOpenVSwitch, self).obj_make_compatible( 358 primitive, '1.1') 359 360 361@base.VersionedObjectRegistry.register 362class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch): 363 """Port profile info for Open vSwitch networks using fast path. 364 365 This profile provides the metadata required to associate a :term:`fast 366 path <Fast Path>` VIF with an :term:`Open vSwitch` port. 367 """ 368 369 # Version 1.0: Initial release 370 # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0 371 # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1 372 # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2 373 VERSION = '1.3' 374 375 fields = { 376 #: Name of the bridge (managed by fast path) to connect to. 377 'bridge_name': fields.StringField(), 378 379 #: Whether the OpenVSwitch network is using hybrid plug. 380 'hybrid_plug': fields.BooleanField(default=False), 381 } 382 383 def obj_make_compatible(self, primitive, target_version): 384 target_version = versionutils.convert_version_to_tuple(target_version) 385 if target_version < (1, 1): 386 super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( 387 primitive, '1.0') 388 elif target_version < (1, 2): 389 super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( 390 primitive, '1.1') 391 elif target_version < (1, 3): 392 super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( 393 primitive, '1.2') 394 else: 395 super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( 396 primitive, '1.3') 397 398 399@removals.removed_class("VIFPortProfileOVSRepresentor", 400 category=PendingDeprecationWarning) 401@base.VersionedObjectRegistry.register 402class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch): 403 """Port profile info for OpenVSwitch networks using a representor. 404 405 This profile provides the metadata required to associate a VIF with a 406 :term:`VF` representor and :term:`Open vSwitch` port. If `representor_name` 407 is specified, it indicates a desire to rename the representor to the given 408 name on plugging. 409 410 .. note:: 411 412 This port profile is provided for backwards compatibility only. 413 414 This interface has been superceded by the one provided by the 415 :class:`DatapathOffloadRepresentor` class, which is now a field element 416 of the :class:`VIFPortProfileBase` class. The ``datapath_offload`` 417 field in port profiles should be used instead. 418 """ 419 420 # Version 1.0: Initial release 421 # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0 422 # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1 423 # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2 424 VERSION = '1.3' 425 426 fields = { 427 #: Name to set on the representor (if set). 428 'representor_name': fields.StringField(nullable=True), 429 430 #: The PCI address of the Virtual Function. 431 'representor_address': fields.PCIAddressField(nullable=True), 432 } 433 434 def obj_make_compatible(self, primitive, target_version): 435 target_version = versionutils.convert_version_to_tuple(target_version) 436 if target_version < (1, 1): 437 super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( 438 primitive, '1.0') 439 elif target_version < (1, 2): 440 super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( 441 primitive, '1.1') 442 elif target_version < (1, 3): 443 super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( 444 primitive, '1.2') 445 else: 446 super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( 447 primitive, '1.3') 448 449 450@base.VersionedObjectRegistry.register 451class VIFPortProfileFPBridge(VIFPortProfileBase): 452 """Port profile info for Linux Bridge networks using fast path. 453 454 This profile provides the metadata required to associate a :term:`fast 455 path <Fast Path>` VIF with a :term:`Linux Bridge` port. 456 """ 457 458 # Version 1.0: Initial release 459 # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0 460 VERSION = '1.1' 461 462 fields = { 463 #: Name of the bridge (managed by fast path) to connect to. 464 'bridge_name': fields.StringField(), 465 } 466 467 def obj_make_compatible(self, primitive, target_version): 468 target_version = versionutils.convert_version_to_tuple(target_version) 469 if target_version < (1, 1): 470 super(VIFPortProfileFPBridge, self).obj_make_compatible( 471 primitive, '1.0') 472 else: 473 super(VIFPortProfileFPBridge, self).obj_make_compatible( 474 primitive, '1.1') 475 476 477@base.VersionedObjectRegistry.register 478class VIFPortProfileFPTap(VIFPortProfileBase): 479 """Port profile info for Calico networks using fast path. 480 481 This profile provides the metadata required to associate a :term:`fast 482 path <Fast Path>` VIF with a :term:`Calico` port. 483 """ 484 485 # Version 1.0: Initial release 486 # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0 487 VERSION = '1.1' 488 489 fields = { 490 #: The MAC address of the host vhostuser port. 491 'mac_address': fields.MACAddressField(nullable=True), 492 } 493 494 def obj_make_compatible(self, primitive, target_version): 495 target_version = versionutils.convert_version_to_tuple(target_version) 496 if target_version < (1, 1): 497 super(VIFPortProfileFPTap, self).obj_make_compatible( 498 primitive, '1.0') 499 else: 500 super(VIFPortProfileFPTap, self).obj_make_compatible( 501 primitive, '1.1') 502 503 504@base.VersionedObjectRegistry.register 505class VIFPortProfile8021Qbg(VIFPortProfileBase): 506 """Port profile info for VEPA 802.1qbg networks. 507 508 This profile provides the metadata required to associate a VIF with a VEPA 509 host device supporting the :term:`802.1Qbg` spec. 510 """ 511 512 # Version 1.0: Initial release 513 # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0 514 VERSION = '1.1' 515 516 fields = { 517 # TODO(stephenfin): Apparently the value 0 is reserved for manager_id, 518 # so should we set 'minimum=1'? 519 # https://libvirt.org/formatdomain.html#elementsNICS 520 521 #: The VSI Manager ID identifies the database containing the VSI type 522 #: and instance definitions. 523 'manager_id': fields.IntegerField(), 524 525 #: The VSI Type ID identifies a VSI type characterizing the network 526 #: access. VSI types are typically managed by network administrator. 527 'type_id': fields.IntegerField(), 528 529 #: The VSI Type Version allows multiple versions of a VSI Type. 530 'type_id_version': fields.IntegerField(), 531 532 #: The VSI Instance ID Identifier is generated when a VSI instance 533 #: (i.e. a virtual interface of a virtual machine) is created. This is 534 #: a globally unique identifier. 535 'instance_id': fields.UUIDField(), 536 } 537 538 def obj_make_compatible(self, primitive, target_version): 539 target_version = versionutils.convert_version_to_tuple(target_version) 540 if target_version < (1, 1): 541 super(VIFPortProfile8021Qbg, self).obj_make_compatible( 542 primitive, '1.0') 543 else: 544 super(VIFPortProfile8021Qbg, self).obj_make_compatible( 545 primitive, '1.1') 546 547 548@base.VersionedObjectRegistry.register 549class VIFPortProfile8021Qbh(VIFPortProfileBase): 550 """Port profile info for VEPA 802.1qbh networks. 551 552 This profile provides the metadata required to associate a VIF with a VEPA 553 host device supporting the :term:`802.1Qbh` spec. 554 """ 555 556 # Version 1.0: Initial release 557 # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0 558 VERSION = '1.1' 559 560 fields = { 561 #: The name of the port profile that is to be applied to this 562 #: interface. This name is resolved by the port profile database into 563 #: the network parameters from the port profile, and those network 564 #: parameters will be applied to this interface. 565 'profile_id': fields.StringField() 566 } 567 568 def obj_make_compatible(self, primitive, target_version): 569 target_version = versionutils.convert_version_to_tuple(target_version) 570 if target_version < (1, 1): 571 super(VIFPortProfile8021Qbh, self).obj_make_compatible( 572 primitive, '1.0') 573 else: 574 super(VIFPortProfile8021Qbh, self).obj_make_compatible( 575 primitive, '1.1') 576 577 578@base.VersionedObjectRegistry.register 579class VIFPortProfileK8sDPDK(VIFPortProfileBase): 580 """Port profile info for Kuryr-Kubernetes DPDK ports. 581 582 This profile provides the metadata required to associate nested DPDK VIF 583 with a Kubernetes pod. 584 """ 585 586 # Version 1.0: Initial release 587 # Version 1.1: VIFPortProfileBase updated to 1.1 from 1.0 588 VERSION = '1.1' 589 590 fields = { 591 #: Specify whether this vif requires L3 setup. 592 'l3_setup': fields.BooleanField(), 593 594 #: String containing URL representing object in Kubernetes v1 API. 595 'selflink': fields.StringField(), 596 597 #: String used in Kubernetes v1 API to identify the server's internal 598 #: version of this object. 599 'resourceversion': fields.StringField() 600 } 601 602 def obj_make_compatible(self, primitive, target_version): 603 target_version = versionutils.convert_version_to_tuple(target_version) 604 if target_version < (1, 1): 605 super(VIFPortProfileK8sDPDK, self).obj_make_compatible( 606 primitive, '1.0') 607 else: 608 super(VIFPortProfileK8sDPDK, self).obj_make_compatible( 609 primitive, '1.1') 610