sriov-agent: Report resource info in heartbeat

Example config for sriov-agent:

sriov_agent.ini:
[sriov_nic]
physical_device_mappings = physnet0:ens5,physnet0:ens6
resource_provider_bandwidths = ens5:100000:100000,ens6:100000:100000

Agent configurations now includes 'resource_provider_bandwidths' and
'resource_provider_inventory_defaults'.

Change-Id: I1af798d404ed94cd30da3f92734bea911bbc3ac7
Co-Authored-By: Lajos Katona <lajos.katona@ericsson.com>
Depends-On: https://review.openstack.org/577220
Partial-Bug: #1578989
See-Also: https://review.openstack.org/502306 (nova spec)
See-Also: https://review.openstack.org/508149 (neutron spec)
This commit is contained in:
Bence Romsics 2018-07-09 16:16:52 +02:00 committed by Lajos Katona
parent f352f9faaa
commit d7d433f729
4 changed files with 115 additions and 11 deletions

View File

@ -43,6 +43,35 @@ sriov_nic_opts = [
"network_device. The network_device in the mapping "
"should appear in the physical_device_mappings "
"list.")),
cfg.ListOpt('resource_provider_bandwidths',
default=[],
help=_("Comma-separated list of "
"<network_device>:<egress_bw>:<ingress_bw> tuples, "
"showing the available bandwidth for the given device "
"in the given direction. The direction is meant from "
"VM perspective. Bandwidth is measured in kilobits per "
"second (kbps). The device must appear in "
"physical_device_mappings as the value. But not all "
"devices in physical_device_mappings must be listed "
"here. For a device not listed here we neither create "
"a resource provider in placement nor report "
"inventories against. An omitted direction means we do "
"not report an inventory for the corresponding "
"class.")),
cfg.DictOpt('resource_provider_inventory_defaults',
default={'allocation_ratio': 1.0,
'min_unit': 1,
'step_size': 1,
'reserved': 0},
help=_("Key:value pairs to specify defaults used "
"while reporting resource provider inventories. "
"Possible keys with their types: "
"allocation_ratio:float, "
"max_unit:int, min_unit:int, "
"reserved:int, step_size:int, "
"See also: "
"https://developer.openstack.org/api-ref/placement/"
"#update-resource-provider-inventories")),
]

View File

@ -24,6 +24,7 @@ from neutron_lib.agent import topics
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants as n_constants
from neutron_lib import context
from neutron_lib.placement import utils as place_utils
from neutron_lib.utils import helpers
from oslo_config import cfg
from oslo_log import log as logging
@ -39,7 +40,9 @@ from neutron.agent import securitygroups_rpc as agent_sg_rpc
from neutron.api.rpc.callbacks import resources
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
from neutron.common import config as common_config
from neutron.common import constants as c_const
from neutron.common import profiler as setup_profiler
from neutron.common import utils as n_utils
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import config
from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
import exceptions as exc
@ -109,7 +112,7 @@ class SriovNicSwitchRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
@profiler.trace_cls("rpc")
class SriovNicSwitchAgent(object):
def __init__(self, physical_devices_mappings, exclude_devices,
polling_interval):
polling_interval, rp_bandwidths, rp_inventory_defaults):
self.polling_interval = polling_interval
self.network_ports = collections.defaultdict(list)
@ -132,6 +135,8 @@ class SriovNicSwitchAgent(object):
self.connection)
configurations = {'device_mappings': physical_devices_mappings,
c_const.RP_BANDWIDTHS: rp_bandwidths,
c_const.RP_INVENTORY_DEFAULTS: rp_inventory_defaults,
'extensions': self.ext_manager.names()}
# TODO(mangelajo): optimize resource_versions (see ovs agent)
@ -427,21 +432,29 @@ class SriovNicAgentConfigParser(object):
cfg.CONF.SRIOV_NIC.physical_device_mappings, unique_keys=False)
self.exclude_devices = config.parse_exclude_devices(
cfg.CONF.SRIOV_NIC.exclude_devices)
self.rp_bandwidths = place_utils.parse_rp_bandwidths(
cfg.CONF.SRIOV_NIC.resource_provider_bandwidths)
self.rp_inventory_defaults = place_utils.parse_rp_inventory_defaults(
cfg.CONF.SRIOV_NIC.resource_provider_inventory_defaults)
self._validate()
def _validate(self):
"""Validate configuration.
Validate that network_device in excluded_device
exists in device mappings
exists in device mappings.
Validate that network_device in resource_provider_bandwidths
exists in device mappings.
"""
dev_net_set = set(itertools.chain.from_iterable(
six.itervalues(self.device_mappings)))
for dev_name in self.exclude_devices.keys():
if dev_name not in dev_net_set:
raise ValueError(_("Device name %(dev_name)s is missing from "
"physical_device_mappings") % {'dev_name':
dev_name})
raise ValueError(_(
"Invalid exclude_devices: "
"Device name %(dev_name)s is missing from "
"physical_device_mappings") % {'dev_name': dev_name})
n_utils.validate_rp_bandwidth(self.rp_bandwidths, dev_net_set)
def main():
@ -453,6 +466,8 @@ def main():
config_parser.parse()
device_mappings = config_parser.device_mappings
exclude_devices = config_parser.exclude_devices
rp_bandwidths = config_parser.rp_bandwidths
rp_inventory_defaults = config_parser.rp_inventory_defaults
except ValueError:
LOG.exception("Failed on Agent configuration parse. "
@ -465,7 +480,9 @@ def main():
try:
agent = SriovNicSwitchAgent(device_mappings,
exclude_devices,
polling_interval)
polling_interval,
rp_bandwidths,
rp_inventory_defaults)
except exc.SriovNicError:
LOG.exception("Agent Initialization Failed")
raise SystemExit(1)

View File

@ -21,6 +21,7 @@ from oslo_utils import uuidutils
from neutron.agent.l2 import l2_agent_extensions_manager as l2_ext_manager
from neutron.agent import rpc as agent_rpc
from neutron.common import constants as c_const
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
@ -53,7 +54,7 @@ class TestSriovAgent(base.BaseTestCase):
'FixedIntervalLoopingCall',
new=MockFixedIntervalLoopingCall)
self.agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
self.agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0, {}, {})
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.eswitch_manager"
".ESwitchManager.get_assigned_devices_info", return_value=set())
@ -81,7 +82,7 @@ class TestSriovAgent(base.BaseTestCase):
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_with_existed_device(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0, {}, {})
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
@ -98,7 +99,7 @@ class TestSriovAgent(base.BaseTestCase):
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_with_not_existed_device(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0, {}, {})
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
@ -118,7 +119,7 @@ class TestSriovAgent(base.BaseTestCase):
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_failed(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0, {}, {})
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
@ -532,6 +533,38 @@ class TestSriovAgent(base.BaseTestCase):
cleaned_port_id = self.agent._clean_network_ports(mac_slot_2)
self.assertEqual({}, self.agent.network_ports)
def test_configurations_has_rp_bandwidth(self):
rp_bandwidth = {'ens7': {'egress': 10000, 'ingress': 10000}}
agent = sriov_nic_agent.SriovNicSwitchAgent(
{}, {}, 0, rp_bandwidth, {})
self.assertIn(c_const.RP_BANDWIDTHS,
agent.agent_state['configurations'])
rp_bandwidths = agent.agent_state['configurations'][
c_const.RP_BANDWIDTHS]
self.assertEqual(rp_bandwidth['ens7'], rp_bandwidths['ens7'])
def test_configurations_has_rp_default_inventory(self):
rp_inventory_values = {
'allocation_ratio': 1.0,
'min_unit': 1,
'step_size': 1,
'reserved': 0
}
agent = sriov_nic_agent.SriovNicSwitchAgent(
{}, {}, 0, {}, rp_inventory_values)
self.assertIn(c_const.RP_INVENTORY_DEFAULTS,
agent.agent_state['configurations'])
rp_inv_defaults = agent.agent_state['configurations'][
c_const.RP_INVENTORY_DEFAULTS]
self.assertListEqual(
sorted(list(rp_inventory_values)),
sorted(list(rp_inv_defaults.keys())))
for inv_key, inv_value in rp_inventory_values.items():
self.assertEqual(inv_value,
rp_inv_defaults[inv_key])
class FakeAgent(object):
def __init__(self):
@ -605,9 +638,22 @@ class TestSRIOVAgentExtensionConfig(base.BaseTestCase):
def test_report_loaded_extension(self, *args):
with mock.patch.object(agent_rpc.PluginReportStateAPI,
'report_state') as mock_report_state:
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0, {}, {})
agent._report_state()
mock_report_state.assert_called_with(
agent.context, agent.agent_state)
self.assertEqual(
['qos'], agent.agent_state['configurations']['extensions'])
class TestSriovNicAgentConfigParser(base.BaseTestCase):
def test__validate_rp_in_dev_mappings(self):
with mock.patch.object(
cfg.CONF.SRIOV_NIC, 'physical_device_mappings',
new=[]), \
mock.patch.object(
cfg.CONF.SRIOV_NIC, 'resource_provider_bandwidths',
new=['no_such_dev_in_dev_mappings:1:1']):
parser = sriov_nic_agent.SriovNicAgentConfigParser()
self.assertRaises(ValueError, parser.parse)

View File

@ -0,0 +1,12 @@
---
features:
- |
New configuration options for neutron-sriov-agent under section
``[sriov_nic]``: ``resource_provider_bandwidths`` and
``resource_provider_inventory_defaults``.
The former controls the ``total`` (available bandwidth) field of the
physical network interface resource provider inventories. It defaults
to not creating resource providers in Placement. The latter can be used
to tune the other fields (``allocation_ratio``, ``min_unit``,
``max_unit``, ``reserved``, ``step_size``) of resource provider
inventories.