ovs-agent: Report resource info in heartbeat
Example config for ovs-agent: ml2_conf.ini: [ovs] bridge_mappings = physnet0:br-test resource_provider_bandwidths = br-test:100000:100000 Agent configurations now includes 'resource_provider_bandwidths' and 'resource_provider_inventory_defaults'. Change-Id: Ib197573e5cdb60ef0db4e7a771c3179bf9d5bb95 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
c9444141b6
commit
f352f9faaa
@ -250,3 +250,6 @@ EXT_PARENT_RESOURCE_MAPPING = {
|
||||
l3.FLOATINGIP: plugin_consts.L3
|
||||
}
|
||||
EXT_PARENT_PREFIX = 'ext_parent'
|
||||
|
||||
RP_BANDWIDTHS = 'resource_provider_bandwidths'
|
||||
RP_INVENTORY_DEFAULTS = 'resource_provider_inventory_defaults'
|
||||
|
@ -817,3 +817,24 @@ def port_ip_changed(new_port, original_port):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def validate_rp_bandwidth(rp_bandwidths, device_names):
|
||||
"""Validate resource provider bandwidths against device names.
|
||||
|
||||
:param rp_bandwidths: Dict containing resource provider bandwidths,
|
||||
in the form:
|
||||
{'phy1': {'ingress': 100, 'egress': 100}}
|
||||
:param device_names: A set of the device names given in bridge_mappings
|
||||
in case of ovs-agent or in physical_device_mappings
|
||||
in case of sriov-agent
|
||||
:raises ValueError: In case of the devices (keys) in the rp_bandwidths dict
|
||||
are not in the device_names set.
|
||||
"""
|
||||
|
||||
for dev_name in rp_bandwidths:
|
||||
if dev_name not in device_names:
|
||||
raise ValueError(_(
|
||||
"Invalid resource_provider_bandwidths: "
|
||||
"Device name %(dev_name)s is missing from "
|
||||
"device mappings") % {'dev_name': dev_name})
|
||||
|
@ -62,6 +62,34 @@ ovs_opts = [
|
||||
"mapping, make sure to disconnect it from the "
|
||||
"integration bridge as it won't be managed by the "
|
||||
"agent anymore.")),
|
||||
cfg.ListOpt('resource_provider_bandwidths',
|
||||
default=[],
|
||||
help=_("Comma-separated list of "
|
||||
"<bridge>:<egress_bw>:<ingress_bw> tuples, showing "
|
||||
"the available bandwidth for the given bridge in the "
|
||||
"given direction. The direction is meant from VM "
|
||||
"perspective. Bandwidth is measured in kilobits per "
|
||||
"second (kbps). The bridge must appear in "
|
||||
"bridge_mappings as the value. But not all bridges in "
|
||||
"bridge_mappings must be listed here. For a bridge 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")),
|
||||
cfg.BoolOpt('use_veth_interconnection', default=False,
|
||||
help=_("Use veths instead of patch ports to interconnect the "
|
||||
"integration bridge to physical networks. "
|
||||
|
@ -30,6 +30,7 @@ from neutron_lib.callbacks import registry
|
||||
from neutron_lib.callbacks import resources as callback_resources
|
||||
from neutron_lib import constants as n_const
|
||||
from neutron_lib import context
|
||||
from neutron_lib.placement import utils as place_utils
|
||||
from neutron_lib.plugins import utils as plugin_utils
|
||||
from neutron_lib.utils import helpers
|
||||
from oslo_config import cfg
|
||||
@ -39,7 +40,7 @@ from oslo_service import loopingcall
|
||||
from oslo_service import systemd
|
||||
from oslo_utils import netutils
|
||||
from osprofiler import profiler
|
||||
from six import moves
|
||||
import six
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.agent.common import ip_lib
|
||||
@ -150,8 +151,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
|
||||
self.use_veth_interconnection = ovs_conf.use_veth_interconnection
|
||||
self.veth_mtu = agent_conf.veth_mtu
|
||||
self.available_local_vlans = set(moves.range(n_const.MIN_VLAN_TAG,
|
||||
n_const.MAX_VLAN_TAG + 1))
|
||||
self.available_local_vlans = set(six.moves.range(
|
||||
n_const.MIN_VLAN_TAG, n_const.MAX_VLAN_TAG + 1))
|
||||
self.tunnel_types = agent_conf.tunnel_types or []
|
||||
self.l2_pop = agent_conf.l2_population
|
||||
# TODO(ethuleau): Change ARP responder so it's not dependent on the
|
||||
@ -187,6 +188,15 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
self.setup_rpc()
|
||||
self.bridge_mappings = self._parse_bridge_mappings(
|
||||
ovs_conf.bridge_mappings)
|
||||
self.rp_bandwidths = place_utils.parse_rp_bandwidths(
|
||||
ovs_conf.resource_provider_bandwidths)
|
||||
|
||||
br_set = set(six.itervalues(self.bridge_mappings))
|
||||
n_utils.validate_rp_bandwidth(self.rp_bandwidths,
|
||||
br_set)
|
||||
self.rp_inventory_defaults = place_utils.parse_rp_inventory_defaults(
|
||||
ovs_conf.resource_provider_inventory_defaults)
|
||||
|
||||
self.setup_physical_bridges(self.bridge_mappings)
|
||||
self.vlan_manager = vlanmanager.LocalVlanManager()
|
||||
|
||||
@ -270,6 +280,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
'host': host,
|
||||
'topic': n_const.L2_AGENT_TOPIC,
|
||||
'configurations': {'bridge_mappings': self.bridge_mappings,
|
||||
c_const.RP_BANDWIDTHS: self.rp_bandwidths,
|
||||
c_const.RP_INVENTORY_DEFAULTS:
|
||||
self.rp_inventory_defaults,
|
||||
'integration_bridge':
|
||||
ovs_conf.integration_bridge,
|
||||
'tunnel_types': self.tunnel_types,
|
||||
|
@ -524,3 +524,27 @@ class TestIECUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
||||
expected_kilobits,
|
||||
utils.bits_to_kilobits(input_bits, self.base_unit)
|
||||
)
|
||||
|
||||
|
||||
class TestRpBandwidthValidator(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRpBandwidthValidator, self).setUp()
|
||||
self.device_name_set = {'ens4', 'ens7'}
|
||||
self.valid_rp_bandwidths = {
|
||||
'ens7': {'egress': 10000, 'ingress': 10000}
|
||||
}
|
||||
self.not_valid_rp_bandwidth = {
|
||||
'ens8': {'egress': 10000, 'ingress': 10000}
|
||||
}
|
||||
|
||||
def test_validate_rp_bandwidth_with_device_names(self):
|
||||
try:
|
||||
utils.validate_rp_bandwidth(self.valid_rp_bandwidths,
|
||||
self.device_name_set)
|
||||
except ValueError:
|
||||
self.fail("validate_rp_bandwidth failed to validate %s" %
|
||||
self.valid_rp_bandwidths)
|
||||
|
||||
self.assertRaises(ValueError, utils.validate_rp_bandwidth,
|
||||
self.not_valid_rp_bandwidth, self.device_name_set)
|
||||
|
@ -2311,6 +2311,31 @@ class TestOvsNeutronAgent(object):
|
||||
br, 'add', mock.Mock(), mock.Mock(), ip)
|
||||
self.assertFalse(br.install_arp_responder.called)
|
||||
|
||||
def test_configurations_has_rp_bandwidth(self):
|
||||
self.assertIn(c_const.RP_BANDWIDTHS,
|
||||
self.agent.agent_state['configurations'])
|
||||
|
||||
def test_configurations_has_rp_default_inventory(self):
|
||||
self.assertIn(c_const.RP_INVENTORY_DEFAULTS,
|
||||
self.agent.agent_state['configurations'])
|
||||
rp_inv_defaults = \
|
||||
self.agent.agent_state['configurations'][
|
||||
c_const.RP_INVENTORY_DEFAULTS]
|
||||
self.assertListEqual(
|
||||
sorted(['reserved', 'min_unit', 'allocation_ratio', 'step_size']),
|
||||
sorted(list(rp_inv_defaults)))
|
||||
self.assertEqual(1.0, rp_inv_defaults['allocation_ratio'])
|
||||
self.assertEqual(1, rp_inv_defaults['min_unit'])
|
||||
self.assertEqual(1, rp_inv_defaults['step_size'])
|
||||
self.assertEqual(0, rp_inv_defaults['reserved'])
|
||||
|
||||
def test__validate_rp_bandwidth_bridges(self):
|
||||
cfg.CONF.set_override('bridge_mappings', [], 'OVS')
|
||||
cfg.CONF.set_override(c_const.RP_BANDWIDTHS,
|
||||
['no_such_br_in_bridge_mappings:1:1'],
|
||||
'OVS')
|
||||
self.assertRaises(ValueError, self._make_agent)
|
||||
|
||||
|
||||
class TestOvsNeutronAgentOFCtl(TestOvsNeutronAgent,
|
||||
ovs_test_base.OVSOFCtlTestBase):
|
||||
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
New configuration options for neutron-ovs-agent under section ``[ovs]``:
|
||||
``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…
Reference in New Issue
Block a user