VIF port config versioned objects and driver plugin library
Define a standalone os-vif python library, inspired by os-brick, to provide a versioned object model for data passed from neutron to nova for VIF port binding, and an API to allow vendors to provide custom plug/unplug actions for execution by Nova. Previously-Approved: Mitaka Blueprint: os-vif-library Change-Id: Iaaccba7432d51181a96ea7b01ba353c178f49e69
This commit is contained in:
792
specs/newton/approved/os-vif-library.rst
Normal file
792
specs/newton/approved/os-vif-library.rst
Normal file
@@ -0,0 +1,792 @@
|
|||||||
|
..
|
||||||
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||||
|
License.
|
||||||
|
|
||||||
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||||
|
|
||||||
|
===========================================================
|
||||||
|
VIF port config versioned objects and driver plugin library
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
https://blueprints.launchpad.net/nova/+spec/os-vif-library
|
||||||
|
|
||||||
|
Define a standalone os-vif python library, inspired by os-brick, to provide
|
||||||
|
a versioned object model for data passed from neutron to nova for VIF port
|
||||||
|
binding, and an API to allow vendors to provide custom plug/unplug actions
|
||||||
|
for execution by Nova.
|
||||||
|
|
||||||
|
Problem description
|
||||||
|
===================
|
||||||
|
|
||||||
|
When plugging VIFs into VM instances there is communication between Nova
|
||||||
|
and Neutron to obtain a dict of port binding metadata. Nova passes this
|
||||||
|
along to the virt drivers which have a set of classes for dealing with
|
||||||
|
different VIF types. In the libvirt case, each class has three methods,
|
||||||
|
one for building the libvirt XML config, one for performing host OS config
|
||||||
|
tasks related to plugging a VIF and one for performing host OS config
|
||||||
|
tasks related to unplugging a VIF.
|
||||||
|
|
||||||
|
Currently, whenever a new Neutron mechanism driver is created, this results
|
||||||
|
in the definition of a new VIF type, and the addition of a new VIF class to
|
||||||
|
the libvirt driver to support it. Due to the wide variety of vendors,
|
||||||
|
there is a potentially limitless number of Neutron mechanisms that need
|
||||||
|
to be dealt with over time. Conversely the number of different libvirt
|
||||||
|
XML configurations is quite small and well defined. There are sometimes
|
||||||
|
new libvirt XML configs defined, as QEMU gains new network backends, but
|
||||||
|
this is fairly rare. Out of 15 different VIF types supported by libvirt's
|
||||||
|
VIF driver today, there are only 5 distinct libvirt XML configurations
|
||||||
|
required. These are illustrated in
|
||||||
|
|
||||||
|
https://wiki.openstack.org/wiki/LibvirtVIFTypeXMLConfigs
|
||||||
|
|
||||||
|
The problem with this architecture is that the Nova libvirt maintainers
|
||||||
|
have task of maintaining the plug/unplug code in the VIF drivers, which
|
||||||
|
is really code that is defined by the needs of the Neutron mechanism.
|
||||||
|
This prevents Neutron project / vendors from adding new VIF types without
|
||||||
|
having a lock-step change in Nova.
|
||||||
|
|
||||||
|
A second related problem, is that the format of the data passed between
|
||||||
|
Nova and Neutron for the VIF port binding is fairly loosely defined. There
|
||||||
|
is no versioning of the information passed between them and no agreed formal
|
||||||
|
specification of what the different fields mean. This data is used both to
|
||||||
|
generate the libvirt XML config and to control the logic of the plug/unplug
|
||||||
|
actions.
|
||||||
|
|
||||||
|
|
||||||
|
Use Cases
|
||||||
|
----------
|
||||||
|
|
||||||
|
The overall use case is to facilitate the creation of new Neutron mechanisms
|
||||||
|
by removing Nova as a bottleneck for work. New features can be implemented
|
||||||
|
entirely in the Neutron codebase (or mechanism specific codebase) with no
|
||||||
|
need to add/change code in Nova, in the common case.
|
||||||
|
|
||||||
|
Proposed change
|
||||||
|
===============
|
||||||
|
|
||||||
|
Inspired by the os-brick library effort started by the Cinder project, the
|
||||||
|
proposal involves creation of a new library module that will be jointly
|
||||||
|
developed by the Neutron & Nova teams, for consumption by both projects.
|
||||||
|
|
||||||
|
This proposal is describing an architecture with the following high level
|
||||||
|
characteristics & split of responsibilities
|
||||||
|
|
||||||
|
- Definition of VIF types and associated config metadata.
|
||||||
|
|
||||||
|
* Owned jointly by Nova and Neutron core reviewer teams
|
||||||
|
* Code shared in os-vif library
|
||||||
|
* Ensures core teams have 100% control over data on
|
||||||
|
the REST API
|
||||||
|
|
||||||
|
- Setup of compute host OS networking stack
|
||||||
|
|
||||||
|
* Owned by Neutron mechanism vendor team
|
||||||
|
* Code distributed by mechanism vendor
|
||||||
|
* Allows vendors to innovate without bottleneck on Nova
|
||||||
|
developers in common case.
|
||||||
|
* In the uncommon, event a new VIF type was required,
|
||||||
|
this would still require os-vif modification with
|
||||||
|
Nova & Neutron core team signoff.
|
||||||
|
|
||||||
|
- Configuration of guest virtual machine VIFs ie libvirt XML
|
||||||
|
|
||||||
|
* Owned by Nova virt driver team
|
||||||
|
* Code distributed as part of Nova virt / VIF driver
|
||||||
|
* Ensures hypervisor driver retains full control over
|
||||||
|
how the guest instances are configured
|
||||||
|
|
||||||
|
Note that while the description below frequently refers to the Nova libvirt
|
||||||
|
driver, this proposal is not considered libvirt specific. The same concepts
|
||||||
|
and requirements for VIF type support exist in all the other virt drivers.
|
||||||
|
They merely support far fewer different VIF types than libvirt, so the
|
||||||
|
problems are not so immediately obvious in them.
|
||||||
|
|
||||||
|
The library will make use of the oslo.versionedobjects module in order to
|
||||||
|
formally define a set of objects to describe the VIF port binding data.
|
||||||
|
The data in this objects will be serialized into JSON, for transmission
|
||||||
|
between Neutron and Nova, just as is done with the current dicts used
|
||||||
|
today. The difference is that by using oslo.versionedobjects, we gain
|
||||||
|
a formal specification and the ability to extend and modify the objects
|
||||||
|
over time in a manner that is more future proof. One can imagine a base
|
||||||
|
object
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from oslo_versionedobjects import base
|
||||||
|
|
||||||
|
class VIFConfig(base.VersionedObject)
|
||||||
|
# Common stuff for all VIFs
|
||||||
|
fields = {
|
||||||
|
# VIF port identifier
|
||||||
|
id: UUIDField()
|
||||||
|
|
||||||
|
# Various common fields see current
|
||||||
|
# nova.network.model.VIF class and related ones
|
||||||
|
...snip...
|
||||||
|
|
||||||
|
# Name of the class used for VIF (un)plugging actions
|
||||||
|
plug: StringField()
|
||||||
|
|
||||||
|
# Port profile metadata - needed for network modes
|
||||||
|
# like OVS, VEPA, etc
|
||||||
|
profile: ObjectField("VIFProfile")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
This base object defines the fields that are common to all the
|
||||||
|
different VIF port binding types. There are a number of these attributes,
|
||||||
|
currently detailed in the VIF class in nova.network.model, or the equiv
|
||||||
|
in Neutron.
|
||||||
|
|
||||||
|
One addition here is a 'plug' field which will be the name of a class
|
||||||
|
that will be used to perform the vendor specific plug/unplug work on the
|
||||||
|
host OS. The supported values for the 'plug' field will be determined
|
||||||
|
by Nova via a stevedore based registration mechanism. Nova can pass
|
||||||
|
this info across to Neutron, so that mechanisms know what plugins have
|
||||||
|
been installed on the Nova compute node too. Tagging the plugin class
|
||||||
|
with a version will also be required to enable upgrades where the
|
||||||
|
Neutron mechanism versions is potentially newer than the nova installed
|
||||||
|
plugin.
|
||||||
|
|
||||||
|
This 'plug' field is what de-couples the VIF types from the vendor specific
|
||||||
|
work, and will thus allow the number of VIFConfig classes to remain at a
|
||||||
|
fairly small finite size, while still allowing arbitary number of Neutron
|
||||||
|
mechanisms to be implemented. As an example, from the current list of VIF
|
||||||
|
types shown at:
|
||||||
|
|
||||||
|
https://wiki.openstack.org/wiki/LibvirtVIFTypeXMLConfigs
|
||||||
|
|
||||||
|
We can see that IVS, IOVISOR, MIDONET and VROUTER all use the same
|
||||||
|
libvirt type=ethernet configuration, but different plug scripts.
|
||||||
|
Similarly there is significant overlap between VIFs that use
|
||||||
|
type=bridge, but with different plug scripts.
|
||||||
|
|
||||||
|
The various VIFConfig subclasses will be created, based on the different
|
||||||
|
bits of information that are currently passed around. NB, this is not
|
||||||
|
covering all the current VIF_TYPE_XXX variants, as a number of them
|
||||||
|
have essentially identical config parameter requirements, and only differ
|
||||||
|
in the plug/unplug actions, hence the point previously about the 'plug'
|
||||||
|
class name. All existing VIF types will be considered legacy. These
|
||||||
|
various config classes will define a completely new set of modern VIF
|
||||||
|
types. In many cases they will closely resemble the existing VIF types,
|
||||||
|
but the key difference is in the data serialization format which will
|
||||||
|
be using oslo.versionedobject serialization instead of dicts. By defining
|
||||||
|
a completely new set of VIF types, we make it easy for Nova to negotiate
|
||||||
|
use of the new types with Neutron. When calling Neutron, Nova will
|
||||||
|
indicate what VIF types it is capable of supporting, and thus Neutron
|
||||||
|
can determine whether it is able to use the new object based VIF types
|
||||||
|
or the legacy anonymous dict based types.
|
||||||
|
|
||||||
|
The following dependant spec describes a mechanism for communicating
|
||||||
|
the list of supported VIF types to Neutron when Nova creates a VIF
|
||||||
|
port.
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/190917/
|
||||||
|
|
||||||
|
What is described in that spec will need some further improvements.
|
||||||
|
Instead of just a list of VIF types, it will need to be a list of
|
||||||
|
VIF types and their versions. This will allow Neutron to back-level
|
||||||
|
the VIF object data to an older version in the event that Neutron
|
||||||
|
is running a newer version of the os-vif library than is installed
|
||||||
|
on the Nova compute host. Second, in addition to the list of VIF
|
||||||
|
types, Nova will also need to provide a list of installed plugins
|
||||||
|
along with their versions.
|
||||||
|
|
||||||
|
So approximately the following set of objects would be defined to
|
||||||
|
represent the new VIF types. It is expected that the result of the
|
||||||
|
'obj_name()' API call (defined by oslo VersionedObject base class)
|
||||||
|
will be used as the VIF type name. This gives clear namespace
|
||||||
|
separation from legacy VIF type names.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class VIFConfigBridge(VIFConfig):
|
||||||
|
fields = {
|
||||||
|
# Name of the host TAP device used as the VIF
|
||||||
|
devname: StringField(nullable=True)
|
||||||
|
|
||||||
|
# Name of the bridge device to attach VIF to
|
||||||
|
bridgename: StringField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFConfigEthernet(VIFConfig):
|
||||||
|
fields = {
|
||||||
|
# Name of the host TAP device used as the VIF
|
||||||
|
devname: StringField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFConfigDirect(VIFConfig):
|
||||||
|
fields = {
|
||||||
|
# Source device NIC name on host (eg eth0)
|
||||||
|
devname: StringField()
|
||||||
|
# An enum of 'vepa', 'passthrough', or 'bridge'
|
||||||
|
mode: DirectModeField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFConfigVHostUser(VIFConfig):
|
||||||
|
fields = {
|
||||||
|
# UNIX socket path
|
||||||
|
path: StringField()
|
||||||
|
|
||||||
|
# Access permission mode
|
||||||
|
mode: StringField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFConfigHostDevice(VIFConfig):
|
||||||
|
fields = {
|
||||||
|
# Host device PCI address
|
||||||
|
devaddr: PCIAddressField()
|
||||||
|
|
||||||
|
# VLAN number
|
||||||
|
vlan: IntegerField()
|
||||||
|
}
|
||||||
|
|
||||||
|
NB, the attributes listed in these classes above are not yet totally
|
||||||
|
comprehensive. At time of implementation, there will be more thorough
|
||||||
|
analysis of current VIF code to ensure that all required attributes
|
||||||
|
are covered.
|
||||||
|
|
||||||
|
This list is based on the information identified in this wiki page
|
||||||
|
|
||||||
|
https://wiki.openstack.org/wiki/LibvirtVIFTypeXMLConfigs
|
||||||
|
|
||||||
|
Some of these will be applicable to other hypervisors too, but there may
|
||||||
|
be a few more vmware/hypervisor/xenapi specific config subclasses needed
|
||||||
|
too. This spec does not attempt to enumerate what those will be yet, but
|
||||||
|
they will be similarly simple and finite set.
|
||||||
|
|
||||||
|
Those looking closely will have see reference to a "VIFProfile" object
|
||||||
|
in the "VIFConfig" class shown earlier. This object corresponds to the
|
||||||
|
data that can be provided in the <portprofile>...</portprofile> XML
|
||||||
|
block. This is required data when a VIF is connected to OpenVSwitch,
|
||||||
|
or when using one of the two VEPA modes. This could have been provided
|
||||||
|
inline in the the VIFConfig subclasses, but there are a few cases
|
||||||
|
where the same data is needed by different VIF types, so breaking it
|
||||||
|
out into a separate object allows better reuse, without increasing
|
||||||
|
the number of VIF types.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class VIFProfile(base.VersionedObject):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class VIFProfile8021QBG(VIFProfile):
|
||||||
|
fields = {
|
||||||
|
managerid: IntegerField(),
|
||||||
|
typeid: IntegerField()
|
||||||
|
typeidversion: IntegerField()
|
||||||
|
instanceid: UUIDField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFProfile8021QBH(VIFProfile):
|
||||||
|
fields = {
|
||||||
|
profileid: StringField()
|
||||||
|
}
|
||||||
|
|
||||||
|
class VIFProfileOpenVSwitch(VIFProfile):
|
||||||
|
fields = {
|
||||||
|
interfaceid: UUIDField()
|
||||||
|
profileid: StringField()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Finally, as alluded to in an earlier paragraph, the library will also need
|
||||||
|
to define an interface for enabling the plug / unplug actions to be performed.
|
||||||
|
This is a quite straightforward abstract python class
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class VIFPlug(object):
|
||||||
|
|
||||||
|
VERSION = "1.0"
|
||||||
|
|
||||||
|
def plug(self, config):
|
||||||
|
raise NotImpementedError()
|
||||||
|
|
||||||
|
def unplug(self, config):
|
||||||
|
raise NotImpementedError()
|
||||||
|
|
||||||
|
The 'config' parameter passed in here will be an instance of the VIFConfig
|
||||||
|
versioned object defined above.
|
||||||
|
|
||||||
|
There will be at least one subclass of this VIFPlug class provided by each
|
||||||
|
Neutron vendor mechanism. These subclass implementations do not need to be
|
||||||
|
part of the os-vif library itself. The mechanism vendors would be expected
|
||||||
|
to distribute them independently, so decomposition of the neutron development
|
||||||
|
is maintained. It is expected the vendors will provide a separate VIFPlug
|
||||||
|
impl for each hypervisor they need to be able to integrate with, so info about
|
||||||
|
the Nova hypervisor must be provided to Neutron when Nova requests creation
|
||||||
|
of a VIF port. The VIFPlug classes must be registered with Nova via the
|
||||||
|
stevedore mechanism, so that Nova can identify the list of implementations
|
||||||
|
it has available, and thus validate requests from Neutron to use a particular
|
||||||
|
plugin. It also allows Nova to tell Neutron which plugins are available for
|
||||||
|
use. The plugins will be versioned too, so that it is clear to Neutron which
|
||||||
|
version of the plugin logic will be executed by Nova.
|
||||||
|
|
||||||
|
The vendors would not be permitted to define new VIFConfig sub-classes, these
|
||||||
|
would remain under control of the os-vif library maintainers (ie Neutron and
|
||||||
|
Nova teams), as any additions to data passed over the REST API must be reviewed
|
||||||
|
and approved by project maintainers. Thus proposals for new VIFConfig classes
|
||||||
|
would be submitted to the os-vif repository where the will be reviewed jointly
|
||||||
|
by the Nova & Neutron representatives working on that library. It is expected
|
||||||
|
that this will be a fairly rare requirement, since most new mechanism can be
|
||||||
|
implemented using one of the many existing VIFConfigs.
|
||||||
|
|
||||||
|
So when a vendor wishes to create a new mechanism, they first decide which
|
||||||
|
VIFConfig implementation(s) they need to target, and populate that with the
|
||||||
|
required information about their VIF. This information is sufficient for
|
||||||
|
the Nova hypervisor driver to config the guest virtual machine. When
|
||||||
|
instantiating the VIFConfig impl, the Neutron vendor will set the 'plug'
|
||||||
|
attribute to refer to the name of the VIFPlug subclass they have implemented
|
||||||
|
with their vendor specific logic. The vendor VIFPlug subclasses must of course
|
||||||
|
be installed on the Nova compute nodes, so Nova can load them.
|
||||||
|
|
||||||
|
When Nova asks Neutron to create the VIF, neutron returns the serialized
|
||||||
|
VIFConfig class, which Nova loads. Nova compute manager passes this down
|
||||||
|
to the virt driver implementation, which instantiates the class defined
|
||||||
|
by the 'plug' attribute. It will then invoke either the 'plug' or 'unplug'
|
||||||
|
method depending on whether it is attaching or detaching a VIF to the
|
||||||
|
guest instance. The hypervisor driver will then configure the guest
|
||||||
|
virtual machine using the data stored in the VIFConfig class.
|
||||||
|
|
||||||
|
When a new Nova talks to an old Neutron, it will obviously be receiving the
|
||||||
|
port binding data in the existing dict format. Nova will have to have some
|
||||||
|
compatibility code to be able to support comsumption of the data in this
|
||||||
|
format. Nova would likely convert the dict on the fly to the new object
|
||||||
|
model. The existing libvirt driver VIF plug/unplug methods would also need
|
||||||
|
to be turned into VIFPlug subclasses. This way new Nova will be able to
|
||||||
|
deal with all pre-existing VIF types that old Neutron knows about, with no
|
||||||
|
loss in functionality.
|
||||||
|
|
||||||
|
When an old Nova talks to a new Neutron, Neutron will have to return the
|
||||||
|
data in the existing legacy port binding format. For this to work, there
|
||||||
|
needs to be a negotiation between Nova and Neutron to opt-in to use of the
|
||||||
|
new VIFConfig object model. With an explicit opt-in required, when an old
|
||||||
|
Nova talks to new Neutron, Neutron will know to return data in the legacy
|
||||||
|
format that Nova can still understand. The obvious implication of this
|
||||||
|
is that any newly developed Neutron mechanisms that rely on the new
|
||||||
|
VIFCOnfig object model exclusively, will not work with legacy Nova
|
||||||
|
deployments. This is not considered to be a significant problem, as the
|
||||||
|
mis-match in Neutron/Nova versions is only a temporary problem as a cloud
|
||||||
|
undergoes a staged update from Kilo to Liberty
|
||||||
|
|
||||||
|
To aid in understanding how this changes from current design, it is helpful
|
||||||
|
to compare the relationships between the objects. Currently there is mostly
|
||||||
|
a 1:1 mapping between Neutron mechanisms, vif types, and virt driver plugins.
|
||||||
|
Thus each new Neutron mechanism has typically needed a new VIF type and
|
||||||
|
virt driver plugin.
|
||||||
|
|
||||||
|
In this new design, there will be the following relationships
|
||||||
|
|
||||||
|
- VIF type <-> VIFConfig class - 1:1 - VIFConfig classes are direct
|
||||||
|
representation of each VIF type - a VIF type is simply the name
|
||||||
|
of the class used to represent the data.
|
||||||
|
|
||||||
|
- Neutron mechanism <-> VIF type - M:N - A single mechanism can use
|
||||||
|
one or more VIF types, a particular choice made at runtime based
|
||||||
|
on usage scenario. Multiple mechanisms will be able to use the
|
||||||
|
same VIF type
|
||||||
|
|
||||||
|
- VIF type <-> VIF plugins - 1:M - a single VIF type can be used with
|
||||||
|
multiple plugins. ie many mechanisms will use the same VIF type, but
|
||||||
|
each supply their own plugin implementation for host OS setup
|
||||||
|
|
||||||
|
The split between VIF plugins and VIF types is key to the goal of
|
||||||
|
limiting the number of new VIF types that are created over time.
|
||||||
|
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
------------
|
||||||
|
|
||||||
|
1. Do nothing. Continue with the current approach where every new Neutron
|
||||||
|
mechanism requires a change to Nova hypervisor VIF driver to support
|
||||||
|
its vendor specific plug/unplug actions. This will make no one happy.
|
||||||
|
|
||||||
|
|
||||||
|
2. Return to the previous approach, where Nova allows loading of out
|
||||||
|
of tree VIF driver plugins for libvirt. This is undesirable for
|
||||||
|
a number of reasons.
|
||||||
|
|
||||||
|
The task of configuring a libvirt guest consists of two halves
|
||||||
|
commonly referred to as backend configuration (ie the host) and
|
||||||
|
frontend configuration (ie what the guest sees). The frontend
|
||||||
|
config is something that the libvirt driver needs to retain
|
||||||
|
direct control over, in order to support various features that
|
||||||
|
are common to all VIFs regardless of backend config.
|
||||||
|
|
||||||
|
In addition the libvirt driver has a set of classes for representing
|
||||||
|
the libvirt XML config of a guest, which need to be capable of
|
||||||
|
representing any VIF config for the guest. These are considered part
|
||||||
|
of the libvirt internal implementation and not a stable API.
|
||||||
|
|
||||||
|
Thirdly, the libvirt VIF driver plugin API has changed in the past
|
||||||
|
and may change again in the future, and the data passed into it is
|
||||||
|
an ill-defined dict of values from the port binding.
|
||||||
|
|
||||||
|
For these reasons there is a strong desire to not hand off the
|
||||||
|
entire implementation of the current libvirt VIF driver class
|
||||||
|
to an external 3rd party.
|
||||||
|
|
||||||
|
|
||||||
|
That all said, this spec does in fact take things back to something
|
||||||
|
that is pretty similar to this previous approach. The key differences
|
||||||
|
and benefits of this spec, are that it defines a set of versioned
|
||||||
|
objects to hold the data that is passed to the 3rd party VIFPlug
|
||||||
|
implementation. The external VIFPlug implementation is only being
|
||||||
|
responsible for the host OS setup tasks - ie the plug/unplug
|
||||||
|
actions. The libvirt driver retains control over guest configuration
|
||||||
|
The VIFPlug driver is isolated from the internal impl and API design
|
||||||
|
of the libvirt hypervisor driver. The commonality is that the Neutron
|
||||||
|
vendor has the ability to retain control of their plug/unplug tasks
|
||||||
|
without Nova getting in the way.
|
||||||
|
|
||||||
|
|
||||||
|
3. Keep the current VIF binding approach, but include the name of an
|
||||||
|
executable program (script) that Nova will invoke to perform the
|
||||||
|
plug/unplug actions.
|
||||||
|
|
||||||
|
This is approximately the same as the proposal in this spec, it is just
|
||||||
|
substituting in-process execution of python code, for out of process
|
||||||
|
execution of a (shell) script. In the case of scripts, the data from
|
||||||
|
the VIF port bindings must be provided to the script, and the proposal
|
||||||
|
was to use environment variables. This is moderately ok if the data
|
||||||
|
is all scalar, but if there is as need to provide non-scalar
|
||||||
|
structured data like dicts/lists, then the environment variable
|
||||||
|
approach is very painful to work with.
|
||||||
|
|
||||||
|
The VIF script approach also involves creation of some formal versioned
|
||||||
|
objects for representing port binding data, but those objects live
|
||||||
|
inside Nova. Since Neutron has the same need to represent the VIF
|
||||||
|
port binding data, it is considered better if we can have an external
|
||||||
|
python module which defines the versioned objects to represent the
|
||||||
|
port binding data, that can be shared between both Nova and Neutron
|
||||||
|
|
||||||
|
It is believed that by defining a formal set of versioned objects
|
||||||
|
to represent the VIF port binding data, and a python abstract class
|
||||||
|
for the plug/unplug actions, we achieve a strict, clean and easily
|
||||||
|
extensible interface for the boudnary between Nova and Neutron,
|
||||||
|
avoiding some of the problems inherant in serializing the data via
|
||||||
|
environment variables. ie the VIFPlug subclasses will stil get to
|
||||||
|
access the well defined VIFConfig class attributes, instead of
|
||||||
|
having to parse environment variables.
|
||||||
|
|
||||||
|
|
||||||
|
4. As per this spec, but keep all the VIFConfig classes in Nova instead
|
||||||
|
of creating a separate os-vif library. The main downside with this
|
||||||
|
is that Neutron will ultimately need to create its own copy of the
|
||||||
|
VIFConfig classes, and there will need to be an agreed serialization
|
||||||
|
format between Nova and Neutron for the VIF port binding metadata
|
||||||
|
passed over the REST API. By having the VIFConfig classes in a
|
||||||
|
library that can be used by both Nova and Neutron directly, we ensure
|
||||||
|
both apps have a unified object model and can leverage the standard
|
||||||
|
oslo.versionedobject serialization format. This brings Neutron/Nova
|
||||||
|
a well defined REST API data format this the data passed between them.
|
||||||
|
|
||||||
|
5. Move responsibility for VIF plug/unplug to Neutron. This would require
|
||||||
|
that Neutron provide an agent to run on every compute node that takes
|
||||||
|
care of the plug/unplug actions. This agent would have to have a plugin
|
||||||
|
API so that each Neutron mechanism can provide its own logic for the
|
||||||
|
plug/nuplug actions. In addition the agent would have to deal with
|
||||||
|
staged upgrades where an old agent works with new Neutron or a new
|
||||||
|
agent works with old Neutron. There would still need to be work done
|
||||||
|
to formalize the VIF config data passed between Neutron and Nova for
|
||||||
|
the purpose of configuring the guest instance. So this alternative is
|
||||||
|
ultimately pretty similar to what is described in this spec. The current
|
||||||
|
proposal can simply be thought of as providing this architecture, but
|
||||||
|
with the agent actually built-in to Nova. Given the current impl of
|
||||||
|
Neutron & Nova, leveraging Nova as the "agent" on the compute nodes is
|
||||||
|
lower effort approach with no strong downsides.
|
||||||
|
|
||||||
|
|
||||||
|
Data model impact
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
There is no change to the database data model.
|
||||||
|
|
||||||
|
|
||||||
|
REST API impact
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This work requires the aforementioned spec to allow Nova to pass details
|
||||||
|
of its supported VIF types to Neutron:
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/190917/
|
||||||
|
|
||||||
|
For existing "legacy" VIF types, the data format passed back by Neutron
|
||||||
|
will not change.
|
||||||
|
|
||||||
|
For the new "modern" VIF types, the data format passed back by Neutron
|
||||||
|
will use the oslo.versionedobjects serialization format, instead of just
|
||||||
|
serializing a plain python dict. In other words, the data will be the
|
||||||
|
result of the following API call
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
jsons.dumps(cfg.obj_to_primitive())
|
||||||
|
|
||||||
|
where cfg is the VIFConfig versioned object. This JSON data is thus
|
||||||
|
formally specified and versioned, improving ability to evolve this
|
||||||
|
in future releases.
|
||||||
|
|
||||||
|
In terms of backwards compatibility there are the following scenarios
|
||||||
|
to consider
|
||||||
|
|
||||||
|
- Old Neutron (Kilo), New Nova (Liberty)
|
||||||
|
|
||||||
|
Nova adds extra info to the request telling Neutron what VIF
|
||||||
|
types and plugins are supported. Neutron doesn't know about
|
||||||
|
this so ignores it, and returns one of the legacy VIF types.
|
||||||
|
Nova libvirt driver transforms this legacy VIF type into a
|
||||||
|
modern VIF type, using one of its a built-in back-compat plugins.
|
||||||
|
So there should be no loss in functionality compared to old
|
||||||
|
Nova
|
||||||
|
|
||||||
|
- New Neutron (Liberty), Old Nova (Kilo)
|
||||||
|
|
||||||
|
Nova does not add any info to the request telling Neutron
|
||||||
|
what VIF types are supported. Neutron assumes that Nova
|
||||||
|
only supports the legacy VIF types and so returns data in
|
||||||
|
that format. Neutron does not attempt to use the modern
|
||||||
|
VIF types at all.
|
||||||
|
|
||||||
|
- New Neutron (Liberty), New Nova (Liberty)
|
||||||
|
|
||||||
|
Nova adds extra info to the request telling Neutron what VIF
|
||||||
|
types and plugins are supported. The neutron mechanism looks
|
||||||
|
at this and decides which VIF type + plugin it wishes to use
|
||||||
|
for the port. Neutron passes back a serialized VIFConfig
|
||||||
|
object instance. Nova libvirt directly uses its modern code
|
||||||
|
path for VIF type handling
|
||||||
|
|
||||||
|
|
||||||
|
- Even-newer Neutron (Mxxxxx), New-ish Nova (Liberty)
|
||||||
|
|
||||||
|
Nova adds extra info to the request telling Neutron what VIF
|
||||||
|
types and plugins are supported. Neutron sees that Nova only
|
||||||
|
supports VIFConfigBridge version 1.0, but it has version 1.3.
|
||||||
|
Neutron thus uses obj_make_compatible() to backlevel the
|
||||||
|
object to version 1.0 before returning the VIF data to Nova.
|
||||||
|
|
||||||
|
- New-ish Neutron (Liberty), Even-newer Nova (Mxxxx)
|
||||||
|
|
||||||
|
Nova adds extra info to the request telling Neutron what VIF
|
||||||
|
types and plugins are supported. Neutron only has version 1.0
|
||||||
|
but Nova supports version 1.3. Nova can trivially handle version
|
||||||
|
1.0, so Neutron can just return data in version 1.0 format
|
||||||
|
and Nova just loads it and runs.
|
||||||
|
|
||||||
|
|
||||||
|
Security impact
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The external VIFPlug classes provided by vendors will be able to run
|
||||||
|
arbitrary code on the compute nodes. This is little different in security
|
||||||
|
risk than the current situation where the libvirt VIF driver plug/unplug
|
||||||
|
method implementations run a fairly arbitrary set of commands on the
|
||||||
|
compute host. One difference though is that the Nova core team will no
|
||||||
|
longer be responsible for reviewing that code, as it will be maintained
|
||||||
|
exclusively by the Neutron mechanism vendor.
|
||||||
|
|
||||||
|
While it is obviously possible to vendors to add malicious code to
|
||||||
|
their plugin. This isn't a complete free for all though - the cloud
|
||||||
|
admin must have taken explicit action to install this plugin on the
|
||||||
|
compute node and have it registered appropriately via stevedore.
|
||||||
|
So this does not allow arbitrary code execution by Neutron.
|
||||||
|
|
||||||
|
Notifications impact
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Other end user impact
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Performance Impact
|
||||||
|
------------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Other deployer impact
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
When deploying new Neutron mechanisms, they will include a python module
|
||||||
|
which must be deployed on each compute host. This provides the host OS
|
||||||
|
plug/unplug logic that will be run when adding VIFs to a guest.
|
||||||
|
|
||||||
|
In other words, while currently a user deploying a mechanism would do
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install neutron-mech-wizzbangnet
|
||||||
|
|
||||||
|
on the networking hosts, in the new system they must also run
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install nova-vif-plugin-wizzbangnet
|
||||||
|
|
||||||
|
on any compute nodes that wish to integrate with this mechanism.
|
||||||
|
|
||||||
|
It is anticipated that the various vendor tools for deploying openstack
|
||||||
|
will be able to automate this extra requirement, so cloud admins will
|
||||||
|
not be appreciably impacted by this.
|
||||||
|
|
||||||
|
Developer impact
|
||||||
|
----------------
|
||||||
|
|
||||||
|
When QEMU/libvirt (or another hypervisor) invents a new way of configuring
|
||||||
|
virtual machine networking, it may be neccessary to define a new versioned
|
||||||
|
object in the os-vif library that is shared between Neutron and Nova. This
|
||||||
|
will involve defining a subclass of VIFConfig, and then implementing the
|
||||||
|
logic in the Nova libvirt driver to handle this new configuration type.
|
||||||
|
Based on historical frequency of such additions in QEMU, it is expected
|
||||||
|
that this will be a rare occurrance.
|
||||||
|
|
||||||
|
When a vendor wishes to implement a new Neutron mechanism, they will have
|
||||||
|
to provide an implementation of the VIFPlug class whose abstract interface
|
||||||
|
is defined in the os-vif library. This vendor specific implementation will
|
||||||
|
not need to be included in the os-vif library itself - it can be distributed
|
||||||
|
and deployed by the vendor themselves. This frees the vendor from having to
|
||||||
|
do a lock-step update to Nova to support their product.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
|
Assignee(s)
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Primary assignee:
|
||||||
|
TBD
|
||||||
|
|
||||||
|
Other contributors:
|
||||||
|
|
||||||
|
Daniel Berrange <berrange@redhat.com> irc:danpb
|
||||||
|
Brent Eagles <beagles@redhat.com> irc: beagles
|
||||||
|
Andreas Scheuring
|
||||||
|
Maxime Leroy
|
||||||
|
Jay Pipies irc: jaypipes
|
||||||
|
|
||||||
|
Work Items
|
||||||
|
----------
|
||||||
|
|
||||||
|
1. Create a new os-vif python module in openstack and/or stackforge
|
||||||
|
|
||||||
|
2. Implement the VIFConfig abstract base class as a versioned object
|
||||||
|
using oslo.versionedobjects.
|
||||||
|
|
||||||
|
3. Agree on and define the minimal set of VIF configurations that
|
||||||
|
need to be supported. This is approximately equal to the number
|
||||||
|
of different libvirt XML configs, plus a few for other virt
|
||||||
|
hypervisors
|
||||||
|
|
||||||
|
4. Create VIFConfig subclasses for each of the configs identified
|
||||||
|
in step 3.
|
||||||
|
|
||||||
|
5. Define the VIFPlug abstract base class for Neutron mechanism
|
||||||
|
vendors to implement
|
||||||
|
|
||||||
|
6. Extend Neutron such that it is able to ask mechansisms to return
|
||||||
|
VIF port data in either the legacy dict format or as a VIFConfig
|
||||||
|
object instance
|
||||||
|
|
||||||
|
7. Extend Nova/Neutron REST interface so that Nova is able to request
|
||||||
|
use of the VIFConfig data format
|
||||||
|
|
||||||
|
8. Add code to Nova to convert the legacy dict format into the new
|
||||||
|
style VIFConfig object format, for back compat with old Neutron
|
||||||
|
|
||||||
|
9. Convert the Neutron mechanisms to be able to use the new VIFConfig
|
||||||
|
object model
|
||||||
|
|
||||||
|
10. Profit
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
The key dependency is to have collaboration between the Nova and
|
||||||
|
Neutron teams in setting up the new os-vif python project, and
|
||||||
|
defining the VIFConfig object model and VIFPlug interface.
|
||||||
|
|
||||||
|
There is also a dependancy in agreeing how to extend the REST
|
||||||
|
API in Neutron to allow Nova to request use of the new data format.
|
||||||
|
This is discussed in more detail in:
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/190917/
|
||||||
|
|
||||||
|
Though some aspects of that might need updating to take account
|
||||||
|
of the proposals in this spec
|
||||||
|
|
||||||
|
Once those are done, the Nova and Neutron teams can progress on their
|
||||||
|
respective work items independently.
|
||||||
|
|
||||||
|
Testing
|
||||||
|
=======
|
||||||
|
|
||||||
|
The current gate CI system includes cover for some of the Neutron
|
||||||
|
mechanisms. Once both Neutron and Nova support the new design,
|
||||||
|
the current CI system will automatically start to test its
|
||||||
|
operation.
|
||||||
|
|
||||||
|
For Neutron mechanisms that are not covered by current CI, it is
|
||||||
|
expected that the respective vendors take on the task of testing
|
||||||
|
their own implementations, as is currently the case for 3rd party
|
||||||
|
CI.
|
||||||
|
|
||||||
|
Documentation Impact
|
||||||
|
====================
|
||||||
|
|
||||||
|
The primary documentation impact is not user facing. The docs required
|
||||||
|
will all be developer facing, so can be done as simple docs inside the
|
||||||
|
respective python projects.
|
||||||
|
|
||||||
|
There will be some specific release notes required to advise cloud admins
|
||||||
|
of considerations during upgrade. In particular when upgrading Nova it
|
||||||
|
will be desired to deploy one or more of the Nova VIF plugins to match
|
||||||
|
the Neutron mechanism(s) that they are currently using. If they fail to
|
||||||
|
deploy the plugin, then the Nova/Neutron negotiation should ensure that
|
||||||
|
Neutron continues to use the legacy VIF type, instead of switching to
|
||||||
|
the modern VIF type.
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
The proposal to add a negotiation between Neuton and Nova for
|
||||||
|
vif port binding types. This is a pre-requisite for this spec
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/190917/
|
||||||
|
|
||||||
|
|
||||||
|
The alternative proposal to introduce a VIF script to the existing
|
||||||
|
VIF port binding data. This spec obsoletes that.
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/162468/
|
||||||
|
|
||||||
|
The alternative proposal to completely outsource hyervisor VIF driver
|
||||||
|
plugins to 3rd parties once again. This spec obsoletes that.
|
||||||
|
|
||||||
|
https://review.openstack.org/#/c/191210/
|
||||||
|
|
||||||
|
|
||||||
|
Basic impl of library suggested by Jay Pipes
|
||||||
|
|
||||||
|
https://github.com/jaypipes/os_vif
|
||||||
|
|
||||||
|
|
||||||
|
Variant of Jay's design, which more closely matches what is
|
||||||
|
described in this spec
|
||||||
|
|
||||||
|
https://github.com/berrange/os_vif/tree/object-model
|
||||||
|
|
||||||
|
History
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. list-table:: Revisions
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - Release Name
|
||||||
|
- Description
|
||||||
|
* - Liberty
|
||||||
|
- Introduced
|
||||||
Reference in New Issue
Block a user