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:
parent
f352f9faaa
commit
d7d433f729
@ -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")),
|
||||
]
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user