Adding a VNIC type for physical functions

This change adds a new VNIC type to distinguish between virtual and
physical functions in SR-IOV.

The new VNIC type 'direct-physical' deviates from the behavior of
'direct' VNICs for virtual functions. While neutron tracks the resource
as a port, it does not currently perform any management functions.
Future changes may extend the segment mapping functionality that is
currently based on agent configuration to include direct types.
However, the direct-physical VNICs will not have functional parity with
the other SR-IOV VNIC types in that quality of service and port security
functionality is not available.

APIImpact
DocImpact: Add description for new 'direct-physical' VNIC type.

Closes-Bug: #1500993

Change-Id: If1ab969c2002c649a3d51635ca2765c262e2d37f
This commit is contained in:
Brent Eagles 2015-11-09 09:26:53 -03:30
parent 851464bbab
commit 2c60278992
6 changed files with 54 additions and 3 deletions

View File

@ -80,7 +80,9 @@ VNIC_NORMAL = 'normal'
VNIC_DIRECT = 'direct'
VNIC_MACVTAP = 'macvtap'
VNIC_BAREMETAL = 'baremetal'
VNIC_TYPES = [VNIC_NORMAL, VNIC_DIRECT, VNIC_MACVTAP, VNIC_BAREMETAL]
VNIC_DIRECT_PHYSICAL = 'direct-physical'
VNIC_TYPES = [VNIC_NORMAL, VNIC_DIRECT, VNIC_MACVTAP, VNIC_BAREMETAL,
VNIC_DIRECT_PHYSICAL]
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {

View File

@ -35,6 +35,7 @@ from neutron.common import constants as n_constants
from neutron.common import topics
from neutron.common import utils as n_utils
from neutron import context
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import config
from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
import exceptions as exc
@ -60,6 +61,13 @@ class SriovNicSwitchRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
def port_update(self, context, **kwargs):
LOG.debug("port_update received")
port = kwargs.get('port')
vnic_type = port.get(portbindings.VNIC_TYPE)
if vnic_type and vnic_type == portbindings.VNIC_DIRECT_PHYSICAL:
LOG.debug("The SR-IOV agent doesn't handle %s ports.",
portbindings.VNIC_DIRECT_PHYSICAL)
return
# Put the port mac address in the updated_devices set.
# Do not store port details, as if they're used for processing
# notifications there is no guarantee the notifications are

View File

@ -63,7 +63,8 @@ class SriovNicSwitchMechanismDriver(api.MechanismDriver):
vif_type=VIF_TYPE_HW_VEB,
vif_details={portbindings.CAP_PORT_FILTER: False},
supported_vnic_types=[portbindings.VNIC_DIRECT,
portbindings.VNIC_MACVTAP],
portbindings.VNIC_MACVTAP,
portbindings.VNIC_DIRECT_PHYSICAL],
supported_pci_vendor_info=None):
"""Initialize base class for SriovNicSwitch L2 agent type.
@ -103,6 +104,17 @@ class SriovNicSwitchMechanismDriver(api.MechanismDriver):
LOG.debug("Refusing to bind due to unsupported pci_vendor device")
return
if vnic_type == portbindings.VNIC_DIRECT_PHYSICAL:
# Physical functions don't support things like QoS properties,
# spoof checking, etc. so we might as well side-step the agent
# for now. The agent also doesn't currently recognize non-VF
# PCI devices so we won't get port status change updates
# either. This should be changed in the future so physical
# functions can use device mapping checks and the plugin can
# get port status updates.
self.try_to_bind(context, None)
return
for agent in context.host_agents(self.agent_type):
LOG.debug("Checking agent: %s", agent)
if agent['alive']:
@ -115,10 +127,12 @@ class SriovNicSwitchMechanismDriver(api.MechanismDriver):
def try_to_bind(self, context, agent):
for segment in context.segments_to_bind:
if self.check_segment(segment, agent):
port_status = (constants.PORT_STATUS_ACTIVE if agent is None
else constants.PORT_STATUS_DOWN)
context.set_binding(segment[api.ID],
self.vif_type,
self._get_vif_details(segment),
constants.PORT_STATUS_DOWN)
port_status)
LOG.debug("Bound using segment: %s", segment)
return True
return False

View File

@ -18,6 +18,7 @@ import mock
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import config # noqa
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import exceptions
from neutron.plugins.ml2.drivers.mech_sriov.agent import sriov_nic_agent
@ -293,6 +294,13 @@ class TestSriovNicSwitchRpcCallbacks(base.BaseTestCase):
self.assertEqual(set([(DEVICE_MAC, PCI_SLOT)]),
self.agent.updated_devices)
def test_port_update_with_vnic_physical_direct(self):
port = self._create_fake_port()
port[portbindings.VNIC_TYPE] = portbindings.VNIC_DIRECT_PHYSICAL
kwargs = {'context': self.context, 'port': port}
self.sriov_rpc_callback.port_update(**kwargs)
self.assertEqual(set(), self.agent.updated_devices)
def test_port_update_without_pci_slot(self):
port = self._create_fake_port()
port['binding:profile'] = None

View File

@ -148,6 +148,10 @@ class SriovSwitchMechVnicTypeTestCase(SriovNicSwitchMechanismBaseTestCase):
self._check_vif_type_for_vnic_type(portbindings.VNIC_MACVTAP,
mech_driver.VIF_TYPE_HW_VEB)
def test_vnic_type_direct_physical(self):
self._check_vif_type_for_vnic_type(portbindings.VNIC_DIRECT_PHYSICAL,
mech_driver.VIF_TYPE_HW_VEB)
class SriovSwitchMechProfileTestCase(SriovNicSwitchMechanismBaseTestCase):
def _check_vif_for_pci_info(self, pci_vendor_info, expected_vif_type):
@ -233,6 +237,15 @@ class SriovSwitchMechVifDetailsTestCase(SriovNicSwitchMechanismBaseTestCase):
self.driver.bind_port(context)
self.assertEqual(constants.PORT_STATUS_DOWN, context._bound_state)
def test_get_vif_details_with_agent_direct_physical(self):
context = TestFakePortContext(self.AGENT_TYPE,
self.AGENTS,
self.VLAN_SEGMENTS,
portbindings.VNIC_DIRECT_PHYSICAL)
self.driver.bind_port(context)
self.assertEqual(constants.PORT_STATUS_ACTIVE, context._bound_state)
class SriovSwitchMechConfigTestCase(SriovNicSwitchMechanismBaseTestCase):
def _set_config(self, pci_devs=['aa:bb']):

View File

@ -0,0 +1,6 @@
---
prelude: >
Add new VNIC type for SR-IOV physical functions.
features:
- Neutron now supports creation of ports for exposing physical functions
as network devices to guests.