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:
@@ -80,7 +80,9 @@ VNIC_NORMAL = 'normal'
|
|||||||
VNIC_DIRECT = 'direct'
|
VNIC_DIRECT = 'direct'
|
||||||
VNIC_MACVTAP = 'macvtap'
|
VNIC_MACVTAP = 'macvtap'
|
||||||
VNIC_BAREMETAL = 'baremetal'
|
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 = {
|
EXTENDED_ATTRIBUTES_2_0 = {
|
||||||
'ports': {
|
'ports': {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ from neutron.common import constants as n_constants
|
|||||||
from neutron.common import topics
|
from neutron.common import topics
|
||||||
from neutron.common import utils as n_utils
|
from neutron.common import utils as n_utils
|
||||||
from neutron import context
|
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 config
|
||||||
from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
|
from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
|
||||||
import exceptions as exc
|
import exceptions as exc
|
||||||
@@ -60,6 +61,13 @@ class SriovNicSwitchRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
|||||||
def port_update(self, context, **kwargs):
|
def port_update(self, context, **kwargs):
|
||||||
LOG.debug("port_update received")
|
LOG.debug("port_update received")
|
||||||
port = kwargs.get('port')
|
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.
|
# Put the port mac address in the updated_devices set.
|
||||||
# Do not store port details, as if they're used for processing
|
# Do not store port details, as if they're used for processing
|
||||||
# notifications there is no guarantee the notifications are
|
# notifications there is no guarantee the notifications are
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ class SriovNicSwitchMechanismDriver(api.MechanismDriver):
|
|||||||
vif_type=VIF_TYPE_HW_VEB,
|
vif_type=VIF_TYPE_HW_VEB,
|
||||||
vif_details={portbindings.CAP_PORT_FILTER: False},
|
vif_details={portbindings.CAP_PORT_FILTER: False},
|
||||||
supported_vnic_types=[portbindings.VNIC_DIRECT,
|
supported_vnic_types=[portbindings.VNIC_DIRECT,
|
||||||
portbindings.VNIC_MACVTAP],
|
portbindings.VNIC_MACVTAP,
|
||||||
|
portbindings.VNIC_DIRECT_PHYSICAL],
|
||||||
supported_pci_vendor_info=None):
|
supported_pci_vendor_info=None):
|
||||||
"""Initialize base class for SriovNicSwitch L2 agent type.
|
"""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")
|
LOG.debug("Refusing to bind due to unsupported pci_vendor device")
|
||||||
return
|
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):
|
for agent in context.host_agents(self.agent_type):
|
||||||
LOG.debug("Checking agent: %s", agent)
|
LOG.debug("Checking agent: %s", agent)
|
||||||
if agent['alive']:
|
if agent['alive']:
|
||||||
@@ -115,10 +127,12 @@ class SriovNicSwitchMechanismDriver(api.MechanismDriver):
|
|||||||
def try_to_bind(self, context, agent):
|
def try_to_bind(self, context, agent):
|
||||||
for segment in context.segments_to_bind:
|
for segment in context.segments_to_bind:
|
||||||
if self.check_segment(segment, agent):
|
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],
|
context.set_binding(segment[api.ID],
|
||||||
self.vif_type,
|
self.vif_type,
|
||||||
self._get_vif_details(segment),
|
self._get_vif_details(segment),
|
||||||
constants.PORT_STATUS_DOWN)
|
port_status)
|
||||||
LOG.debug("Bound using segment: %s", segment)
|
LOG.debug("Bound using segment: %s", segment)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import mock
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import uuidutils
|
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 config # noqa
|
||||||
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import exceptions
|
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import exceptions
|
||||||
from neutron.plugins.ml2.drivers.mech_sriov.agent import sriov_nic_agent
|
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.assertEqual(set([(DEVICE_MAC, PCI_SLOT)]),
|
||||||
self.agent.updated_devices)
|
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):
|
def test_port_update_without_pci_slot(self):
|
||||||
port = self._create_fake_port()
|
port = self._create_fake_port()
|
||||||
port['binding:profile'] = None
|
port['binding:profile'] = None
|
||||||
|
|||||||
@@ -148,6 +148,10 @@ class SriovSwitchMechVnicTypeTestCase(SriovNicSwitchMechanismBaseTestCase):
|
|||||||
self._check_vif_type_for_vnic_type(portbindings.VNIC_MACVTAP,
|
self._check_vif_type_for_vnic_type(portbindings.VNIC_MACVTAP,
|
||||||
mech_driver.VIF_TYPE_HW_VEB)
|
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):
|
class SriovSwitchMechProfileTestCase(SriovNicSwitchMechanismBaseTestCase):
|
||||||
def _check_vif_for_pci_info(self, pci_vendor_info, expected_vif_type):
|
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.driver.bind_port(context)
|
||||||
self.assertEqual(constants.PORT_STATUS_DOWN, context._bound_state)
|
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):
|
class SriovSwitchMechConfigTestCase(SriovNicSwitchMechanismBaseTestCase):
|
||||||
def _set_config(self, pci_devs=['aa:bb']):
|
def _set_config(self, pci_devs=['aa:bb']):
|
||||||
|
|||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user