Report pkt processing capacity on Neutron agent RP
Report the packet processing capacity on the Neutron agent resource provider to Placement as the new 'NET_PACKET_RATE_KILOPACKET_PER_SEC' or 'NET_PACKET_RATE_[E|I]GR_KILOPACKET_PER_SEC' resource inventory. This is similar to how the bandwidth resource is reported today. Partial-Bug: #1922237 See-Also: https://review.opendev.org/785236 Change-Id: I8deefbeed4b4b51dd20062df62c8891fee3ebf9d
This commit is contained in:
parent
76a99f9a14
commit
c2bc676183
@ -81,6 +81,8 @@ class PlacementState(object):
|
||||
def __init__(self,
|
||||
rp_bandwidths,
|
||||
rp_inventory_defaults,
|
||||
rp_pkt_processing,
|
||||
rp_pkt_processing_inventory_defaults,
|
||||
driver_uuid_namespace,
|
||||
agent_type,
|
||||
hypervisor_rps,
|
||||
@ -89,6 +91,8 @@ class PlacementState(object):
|
||||
client):
|
||||
self._rp_bandwidths = rp_bandwidths
|
||||
self._rp_inventory_defaults = rp_inventory_defaults
|
||||
self._rp_pp = rp_pkt_processing
|
||||
self._rp_pp_inventory_defaults = rp_pkt_processing_inventory_defaults
|
||||
self._driver_uuid_namespace = driver_uuid_namespace
|
||||
self._agent_type = agent_type
|
||||
self._hypervisor_rps = hypervisor_rps
|
||||
@ -219,7 +223,36 @@ class PlacementState(object):
|
||||
|
||||
return rp_traits
|
||||
|
||||
def deferred_update_resource_provider_inventories(self):
|
||||
def _deferred_update_rp_pp_inventory(self):
|
||||
agent_rp_inventories = []
|
||||
|
||||
for hypervisor, pp_values in self._rp_pp.items():
|
||||
agent_rp_uuid = place_utils.agent_resource_provider_uuid(
|
||||
self._driver_uuid_namespace, hypervisor)
|
||||
|
||||
inventories = {}
|
||||
for direction, rp_class in (
|
||||
(nlib_const.EGRESS_DIRECTION,
|
||||
orc.NET_PACKET_RATE_EGR_KILOPACKET_PER_SEC),
|
||||
(nlib_const.INGRESS_DIRECTION,
|
||||
orc.NET_PACKET_RATE_IGR_KILOPACKET_PER_SEC),
|
||||
(nlib_const.ANY_DIRECTION,
|
||||
orc.NET_PACKET_RATE_KILOPACKET_PER_SEC)):
|
||||
if pp_values.get(direction):
|
||||
inventory = dict(self._rp_pp_inventory_defaults)
|
||||
inventory['total'] = pp_values[direction]
|
||||
inventories[rp_class] = inventory
|
||||
|
||||
if inventories:
|
||||
agent_rp_inventories.append(
|
||||
DeferredCall(
|
||||
self._client.update_resource_provider_inventories,
|
||||
resource_provider_uuid=agent_rp_uuid,
|
||||
inventories=inventories))
|
||||
|
||||
return agent_rp_inventories
|
||||
|
||||
def _deferred_update_rp_bw_inventory(self):
|
||||
rp_inventories = []
|
||||
|
||||
for device, bw_values in self._rp_bandwidths.items():
|
||||
@ -234,7 +267,7 @@ class PlacementState(object):
|
||||
orc.NET_BW_EGR_KILOBIT_PER_SEC),
|
||||
(nlib_const.INGRESS_DIRECTION,
|
||||
orc.NET_BW_IGR_KILOBIT_PER_SEC)):
|
||||
if bw_values[direction] is not None:
|
||||
if bw_values.get(direction):
|
||||
inventory = dict(self._rp_inventory_defaults)
|
||||
inventory['total'] = bw_values[direction]
|
||||
inventories[rp_class] = inventory
|
||||
@ -248,6 +281,15 @@ class PlacementState(object):
|
||||
|
||||
return rp_inventories
|
||||
|
||||
def deferred_update_resource_provider_inventories(self):
|
||||
bw_inventory = self._deferred_update_rp_bw_inventory()
|
||||
pp_inventory = self._deferred_update_rp_pp_inventory()
|
||||
|
||||
inventories = []
|
||||
inventories.extend(bw_inventory)
|
||||
inventories.extend(pp_inventory)
|
||||
return inventories
|
||||
|
||||
def deferred_sync(self):
|
||||
state = []
|
||||
state += self.deferred_update_traits()
|
||||
|
@ -18,6 +18,7 @@ from neutron_lib.api.definitions import agent_resources_synced
|
||||
from neutron_lib.callbacks import events
|
||||
from neutron_lib.callbacks import registry
|
||||
from neutron_lib.callbacks import resources
|
||||
from neutron_lib import constants as n_const
|
||||
from neutron_lib.placement import client as place_client
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.services import base as service_base
|
||||
@ -130,6 +131,17 @@ class PlacementReportPlugin(service_base.ServicePluginBase):
|
||||
'resource_provider_bandwidths'],
|
||||
rp_inventory_defaults=configurations[
|
||||
'resource_provider_inventory_defaults'],
|
||||
# RP_PP_WITHOUT_DIRECTION and RP_PP_WITH_DIRECTION are mutually
|
||||
# exclusive options. Use the one that was provided or fallback to
|
||||
# an empty dict.
|
||||
rp_pkt_processing=(
|
||||
configurations[n_const.RP_PP_WITHOUT_DIRECTION]
|
||||
if configurations.get(
|
||||
n_const.RP_PP_WITHOUT_DIRECTION)
|
||||
else configurations.get(
|
||||
n_const.RP_PP_WITH_DIRECTION, {})),
|
||||
rp_pkt_processing_inventory_defaults=configurations.get(
|
||||
n_const.RP_PP_INVENTORY_DEFAULTS, {}),
|
||||
driver_uuid_namespace=uuid_ns,
|
||||
agent_type=agent['agent_type'],
|
||||
hypervisor_rps=hypervisor_rps,
|
||||
|
@ -54,6 +54,8 @@ class PlacementStateTestCase(base.BaseTestCase):
|
||||
self.kwargs = {
|
||||
'rp_bandwidths': {},
|
||||
'rp_inventory_defaults': {},
|
||||
'rp_pkt_processing': {},
|
||||
'rp_pkt_processing_inventory_defaults': {},
|
||||
'driver_uuid_namespace': self.driver_uuid_namespace,
|
||||
'agent_type': 'fake agent type',
|
||||
'hypervisor_rps': {
|
||||
@ -225,7 +227,7 @@ class PlacementStateTestCase(base.BaseTestCase):
|
||||
set(['CUSTOM_VNIC_TYPE_NORMAL'])],
|
||||
actual_traits)
|
||||
|
||||
def test_deferred_update_resource_provider_inventories(self):
|
||||
def test_deferred_update_resource_provider_inventories_bw(self):
|
||||
self.kwargs.update({
|
||||
'device_mappings': {
|
||||
'physnet0': ['eth0'],
|
||||
@ -255,3 +257,67 @@ class PlacementStateTestCase(base.BaseTestCase):
|
||||
'total': 100,
|
||||
'step_size': 10,
|
||||
'max_unit': 50}})
|
||||
|
||||
def test_deferred_update_resource_provider_inventories_pp_direction(self):
|
||||
self.kwargs.update({
|
||||
'rp_pkt_processing': {
|
||||
'fakehost': {'egress': 100, 'ingress': 200},
|
||||
},
|
||||
'rp_pkt_processing_inventory_defaults': {
|
||||
'step_size': 10,
|
||||
'max_unit': 50,
|
||||
},
|
||||
})
|
||||
state = placement_report.PlacementState(**self.kwargs)
|
||||
|
||||
for deferred in state.deferred_update_resource_provider_inventories():
|
||||
deferred.execute()
|
||||
|
||||
# uuid below generated by the following command:
|
||||
# uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost'
|
||||
expected_calls = [
|
||||
mock.call(
|
||||
resource_provider_uuid=uuid.UUID(
|
||||
'c0b4abe5-516f-54b8-b965-ff94060dcbcc'),
|
||||
inventories={
|
||||
# TODO(przszc): Replace hard-coded resource classes names
|
||||
# with os-resource-classes lib.
|
||||
'NET_PACKET_RATE_EGR_KILOPACKET_PER_SEC': {
|
||||
'total': 100,
|
||||
'step_size': 10,
|
||||
'max_unit': 50},
|
||||
'NET_PACKET_RATE_IGR_KILOPACKET_PER_SEC': {
|
||||
'total': 200,
|
||||
'step_size': 10,
|
||||
'max_unit': 50}})]
|
||||
self.client_mock.update_resource_provider_inventories.assert_has_calls(
|
||||
expected_calls)
|
||||
|
||||
def test_deferred_update_resource_provider_inventories_pp(self):
|
||||
self.kwargs.update({
|
||||
'rp_pkt_processing': {
|
||||
'fakehost': {'any': 300},
|
||||
},
|
||||
'rp_pkt_processing_inventory_defaults': {
|
||||
'step_size': 1,
|
||||
'max_unit': 5,
|
||||
},
|
||||
})
|
||||
state = placement_report.PlacementState(**self.kwargs)
|
||||
|
||||
for deferred in state.deferred_update_resource_provider_inventories():
|
||||
deferred.execute()
|
||||
|
||||
# uuid below generated by the following command:
|
||||
# uuid -v5 '00000000-0000-0000-0000-000000000001' 'fakehost'
|
||||
expected_calls = [
|
||||
mock.call(
|
||||
resource_provider_uuid=uuid.UUID(
|
||||
'c0b4abe5-516f-54b8-b965-ff94060dcbcc'),
|
||||
inventories={
|
||||
'NET_PACKET_RATE_KILOPACKET_PER_SEC': {
|
||||
'total': 300,
|
||||
'step_size': 1,
|
||||
'max_unit': 5}})]
|
||||
self.client_mock.update_resource_provider_inventories.assert_has_calls(
|
||||
expected_calls)
|
||||
|
@ -249,6 +249,86 @@ class PlacementReportPluginTestCases(test_plugin.Ml2PluginV2TestCase):
|
||||
self.assertEqual(1, mock_queue_event.call_count)
|
||||
mock_list_rps.assert_called_once_with(name='hypervisor0')
|
||||
|
||||
def test__sync_placement_state_rp_pkt_processing_with_direction(self):
|
||||
agent = {
|
||||
'agent_type': 'test_mechanism_driver_agent',
|
||||
'configurations': {
|
||||
'resource_provider_bandwidths': {},
|
||||
'resource_provider_inventory_defaults': {},
|
||||
'resource_provider_packet_processing_with_direction': {
|
||||
'fake host': {'egress': 1, 'ingress': 2}
|
||||
},
|
||||
'resource_provider_packet_processing_inventory_defaults': {
|
||||
'allocation_ratio': 1, 'min_unit': 1, 'step_size': 1
|
||||
},
|
||||
},
|
||||
'host': 'fake host',
|
||||
}
|
||||
agent_db = mock.Mock()
|
||||
mock_state = mock.Mock(return_value=[])
|
||||
|
||||
with mock.patch.object(self.service_plugin._batch_notifier,
|
||||
'queue_event') as mock_queue_event, \
|
||||
mock.patch('neutron.agent.common.placement_report.PlacementState',
|
||||
return_value=mock_state) as mock_placement_state:
|
||||
|
||||
self.service_plugin._sync_placement_state(agent, agent_db)
|
||||
|
||||
self.assertEqual(1, mock_queue_event.call_count)
|
||||
mock_placement_state.assert_called_once_with(
|
||||
rp_pkt_processing={'fake host': {'egress': 1, 'ingress': 2}},
|
||||
rp_pkt_processing_inventory_defaults={
|
||||
'allocation_ratio': 1, 'min_unit': 1, 'step_size': 1},
|
||||
rp_bandwidths=mock.ANY,
|
||||
rp_inventory_defaults=mock.ANY,
|
||||
driver_uuid_namespace=mock.ANY,
|
||||
agent_type=mock.ANY,
|
||||
hypervisor_rps=mock.ANY,
|
||||
device_mappings=mock.ANY,
|
||||
supported_vnic_types=mock.ANY,
|
||||
client=mock.ANY)
|
||||
mock_state.deferred_sync.assert_called_once()
|
||||
|
||||
def test__sync_placement_state_rp_pkt_processing_without_direction(self):
|
||||
agent = {
|
||||
'agent_type': 'test_mechanism_driver_agent',
|
||||
'configurations': {
|
||||
'resource_provider_bandwidths': {},
|
||||
'resource_provider_inventory_defaults': {},
|
||||
'resource_provider_packet_processing_without_direction': {
|
||||
'fake host': {'any': 1}
|
||||
},
|
||||
'resource_provider_packet_processing_inventory_defaults': {
|
||||
'allocation_ratio': 1, 'min_unit': 1, 'step_size': 1
|
||||
},
|
||||
},
|
||||
'host': 'fake host',
|
||||
}
|
||||
agent_db = mock.Mock()
|
||||
mock_state = mock.Mock(return_value=[])
|
||||
|
||||
with mock.patch.object(self.service_plugin._batch_notifier,
|
||||
'queue_event') as mock_queue_event, \
|
||||
mock.patch('neutron.agent.common.placement_report.PlacementState',
|
||||
return_value=mock_state) as mock_placement_state:
|
||||
|
||||
self.service_plugin._sync_placement_state(agent, agent_db)
|
||||
|
||||
self.assertEqual(1, mock_queue_event.call_count)
|
||||
mock_placement_state.assert_called_once_with(
|
||||
rp_pkt_processing={'fake host': {'any': 1}},
|
||||
rp_pkt_processing_inventory_defaults={
|
||||
'allocation_ratio': 1, 'min_unit': 1, 'step_size': 1},
|
||||
rp_bandwidths=mock.ANY,
|
||||
rp_inventory_defaults=mock.ANY,
|
||||
driver_uuid_namespace=mock.ANY,
|
||||
agent_type=mock.ANY,
|
||||
hypervisor_rps=mock.ANY,
|
||||
device_mappings=mock.ANY,
|
||||
supported_vnic_types=mock.ANY,
|
||||
client=mock.ANY)
|
||||
mock_state.deferred_sync.assert_called_once()
|
||||
|
||||
|
||||
class PlacementReporterAgentsTestCases(test_plugin.Ml2PluginV2TestCase):
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Report packet processing capacity on the OVS agent resource provider as
|
||||
the new ``NET_PACKET_RATE_KILOPACKET_PER_SEC``,
|
||||
``NET_PACKET_RATE_EGR_KILOPACKET_PER_SEC`` or
|
||||
``NET_PACKET_RATE_IGR_KILOPACKET_PER_SEC`` resource inventory. This is
|
||||
similar to how the bandwidth resource is reported today. The former
|
||||
is used for non-hardware-offloaded OVS deployments, where packets
|
||||
processed from both ingress and egress directions are handled by the same
|
||||
set of CPU cores. Remaining inventories are used for hardware-offloaded
|
||||
OVS, where the incoming and outgoing packets are handled by independent
|
||||
hardware resources.
|
Loading…
Reference in New Issue
Block a user