macvtap: ML2 mech driver for macvtap network attachments

This driver uses the vif_type 'macvtap'. It enriches the vif_details
with the corresponding attributes required by nova [1] to support
macvtap attachments for libvirt qemu/kvm guests.

The review is submitted in three parts:
 - Part 1
    Common functions that are used by the ml2 driver and the agent
 - Part 2 (this part)
     The Mechanism Driver to support port binding for macvtap attachments
 - Part 3
    The Macvtap L2 Agent.

[1] https://review.openstack.org/#/c/182283

Change-Id: I206f58a21c36e55de957d8a23993aa9bc26d1595
Partial-Bug: #1480979
This commit is contained in:
Andreas Scheuring 2015-08-03 15:11:20 +02:00
parent bfcad8eec7
commit eb9bda12d2
6 changed files with 188 additions and 0 deletions

View File

@ -46,6 +46,9 @@ PROFILE = 'binding:profile'
CAP_PORT_FILTER = 'port_filter'
OVS_HYBRID_PLUG = 'ovs_hybrid_plug'
VIF_DETAILS_VLAN = 'vlan'
VIF_DETAILS_MACVTAP_SOURCE = 'macvtap_source'
VIF_DETAILS_MACVTAP_MODE = 'macvtap_mode'
VIF_DETAILS_PHYSICAL_INTERFACE = 'physical_interface'
# The keys below are used in the VIF_DETAILS attribute to convey
# information related to the configuration of the vhost-user VIF driver.
@ -63,6 +66,10 @@ VHOST_USER_SOCKET = 'vhostuser_socket'
# method should be used when binding the
# vhost-user vif.
VHOST_USER_OVS_PLUG = 'vhostuser_ovs_plug'
# VIF_TYPE: vif_types are required by Nova to determine which vif_driver to
# use to attach a virtual server to the network
# - vhost-user: The vhost-user interface type is a standard virtio interface
# provided by qemu 2.1+. This constant defines the neutron side
# of the vif binding type to provide a common definition
@ -75,7 +82,15 @@ VIF_TYPE_DISTRIBUTED = 'distributed'
VIF_TYPE_OVS = 'ovs'
VIF_TYPE_BRIDGE = 'bridge'
VIF_TYPE_OTHER = 'other'
# vif_type_macvtap: Tells Nova that the macvtap vif_driver should be used to
# create a vif. It does not require the VNIC_TYPE_MACVTAP,
# which is defined further below. E.g. Macvtap agent uses
# vnic_type 'normal'.
VIF_TYPE_MACVTAP = 'macvtap'
# VNIC_TYPE: It's used to determine which mechanism driver to use to bind a
# port. It can be specified via the Neutron API. Default is normal,
# used by OVS and LinuxBridge agent.
VNIC_NORMAL = 'normal'
VNIC_DIRECT = 'direct'
VNIC_MACVTAP = 'macvtap'

View File

@ -0,0 +1,80 @@
# Copyright (c) 2016 IBM Corp.
#
# All Rights Reserved.
#
# 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 oslo_log import log
from neutron.common import constants
from neutron.extensions import portbindings
from neutron.plugins.common import constants as p_constants
from neutron.plugins.ml2 import driver_api as api
from neutron.plugins.ml2.drivers.macvtap import macvtap_common
from neutron.plugins.ml2.drivers import mech_agent
LOG = log.getLogger(__name__)
MACVTAP_MODE_BRIDGE = 'bridge'
class MacvtapMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
"""Attach to networks using Macvtap L2 agent.
The MacvtapMechanismDriver integrates the ml2 plugin with the
macvtap L2 agent. Port binding with this driver requires the
macvtap agent to be running on the port's host, and that agent
to have connectivity to at least one segment of the port's
network.
"""
def __init__(self):
super(MacvtapMechanismDriver, self).__init__(
constants.AGENT_TYPE_MACVTAP,
portbindings.VIF_TYPE_MACVTAP,
{portbindings.CAP_PORT_FILTER: False})
def get_allowed_network_types(self, agent):
return [p_constants.TYPE_FLAT, p_constants.TYPE_VLAN]
def get_mappings(self, agent):
return agent['configurations'].get('interface_mappings', {})
def check_vlan_transparency(self, context):
"""Macvtap driver vlan transparency support."""
return False
def try_to_bind_segment_for_agent(self, context, segment, agent):
if self.check_segment_for_agent(segment, agent):
vif_details_segment = self.vif_details
mappings = self.get_mappings(agent)
interface = mappings[segment['physical_network']]
network_type = segment[api.NETWORK_TYPE]
if network_type == p_constants.TYPE_VLAN:
vlan_id = segment[api.SEGMENTATION_ID]
macvtap_src = macvtap_common.get_vlan_device_name(interface,
vlan_id)
vif_details_segment['vlan'] = vlan_id
else:
macvtap_src = interface
vif_details_segment['physical_interface'] = interface
vif_details_segment['macvtap_source'] = macvtap_src
vif_details_segment['macvtap_mode'] = MACVTAP_MODE_BRIDGE
LOG.debug("Macvtap vif_details added to context binding: %s",
vif_details_segment)
context.set_binding(segment[api.ID], self.vif_type,
vif_details_segment)
return True
return False

View File

@ -0,0 +1,92 @@
# Copyright (c) 2015 IBM Corp.
# All Rights Reserved.
#
# 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 neutron.common import constants
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers.macvtap.mech_driver import mech_macvtap
from neutron.tests.unit.plugins.ml2 import _test_mech_agent as base
class MacvtapMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
VIF_TYPE = portbindings.VIF_TYPE_MACVTAP
CAP_PORT_FILTER = False
AGENT_TYPE = constants.AGENT_TYPE_MACVTAP
GOOD_MAPPINGS = {'fake_physical_network': 'fake_if'}
GOOD_CONFIGS = {'interface_mappings': GOOD_MAPPINGS}
BAD_MAPPINGS = {'wrong_physical_network': 'wrong_if'}
BAD_CONFIGS = {'interface_mappings': BAD_MAPPINGS}
AGENTS = [{'alive': True,
'configurations': GOOD_CONFIGS,
'host': 'host'}]
AGENTS_DEAD = [{'alive': False,
'configurations': GOOD_CONFIGS,
'host': 'dead_host'}]
AGENTS_BAD = [{'alive': False,
'configurations': GOOD_CONFIGS,
'host': 'bad_host_1'},
{'alive': True,
'configurations': BAD_CONFIGS,
'host': 'bad_host_2'}]
def setUp(self):
super(MacvtapMechanismBaseTestCase, self).setUp()
self.driver = mech_macvtap.MacvtapMechanismDriver()
self.driver.initialize()
class MacvtapMechanismGenericTestCase(MacvtapMechanismBaseTestCase,
base.AgentMechanismGenericTestCase):
pass
class MacvtapMechanismFlatTestCase(MacvtapMechanismBaseTestCase,
base.AgentMechanismFlatTestCase):
def test_type_flat_vif_details(self):
context = base.FakePortContext(self.AGENT_TYPE,
self.AGENTS,
self.FLAT_SEGMENTS,
vnic_type=self.VNIC_TYPE)
self.driver.bind_port(context)
vif_details = context._bound_vif_details
self.assertIsNone(vif_details.get(portbindings.VIF_DETAILS_VLAN))
self.assertEqual("bridge", vif_details.get(
portbindings.VIF_DETAILS_MACVTAP_MODE))
self.assertEqual("fake_if", vif_details.get(
portbindings.VIF_DETAILS_PHYSICAL_INTERFACE))
self.assertEqual("fake_if", vif_details.get(
portbindings.VIF_DETAILS_MACVTAP_SOURCE))
class MacvtapMechanismVlanTestCase(MacvtapMechanismBaseTestCase,
base.AgentMechanismVlanTestCase):
def test_type_vlan_vif_details(self):
context = base.FakePortContext(self.AGENT_TYPE,
self.AGENTS,
self.VLAN_SEGMENTS,
vnic_type=self.VNIC_TYPE)
self.driver.bind_port(context)
vif_details = context._bound_vif_details
self.assertEqual(1234, vif_details.get(portbindings.VIF_DETAILS_VLAN))
self.assertEqual("bridge", vif_details.get(
portbindings.VIF_DETAILS_MACVTAP_MODE))
self.assertEqual("fake_if", vif_details.get(
portbindings.VIF_DETAILS_PHYSICAL_INTERFACE))
self.assertEqual("fake_if.1234", vif_details.get(
portbindings.VIF_DETAILS_MACVTAP_SOURCE))

View File

@ -91,6 +91,7 @@ neutron.ml2.mechanism_drivers =
logger = neutron.tests.unit.plugins.ml2.drivers.mechanism_logger:LoggerMechanismDriver
test = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriver
linuxbridge = neutron.plugins.ml2.drivers.linuxbridge.mech_driver.mech_linuxbridge:LinuxbridgeMechanismDriver
macvtap = neutron.plugins.ml2.drivers.macvtap.mech_driver.mech_macvtap:MacvtapMechanismDriver
openvswitch = neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch:OpenvswitchMechanismDriver
l2population = neutron.plugins.ml2.drivers.l2pop.mech_driver:L2populationMechanismDriver
sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver.mech_driver:SriovNicSwitchMechanismDriver