Adding FDB population agent extension
The purpose of this extension is updating the FDB table upon changes of normal port instances thus enabling communication between direct port SR-IOV instances and normal port instances. Additionally enabling communication to direct port instances with floating ips. Support for OVS agent and linux bridge. DocImpact Change-Id: I61a8aacb1b21b2a6e452389633d7dcccf9964fea Closes-Bug: #1492228 Closes-Bug: #1527991
This commit is contained in:
parent
93a7bef28b
commit
2c8f61b816
172
neutron/agent/l2/extensions/fdb_population.py
Normal file
172
neutron/agent/l2/extensions/fdb_population.py
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
# Copyright (c) 2016 Mellanox Technologies, Ltd
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from neutron._i18n import _, _LE, _LW
|
||||||
|
from neutron.agent.l2 import agent_extension
|
||||||
|
from neutron.agent.linux import bridge_lib
|
||||||
|
from neutron.common import utils as n_utils
|
||||||
|
from neutron.plugins.ml2.drivers.linuxbridge.agent.common import (
|
||||||
|
constants as linux_bridge_constants)
|
||||||
|
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
|
||||||
|
constants as ovs_constants)
|
||||||
|
|
||||||
|
# if shared_physical_device_mappings is not configured KeyError will be thrown
|
||||||
|
fdb_population_opt = [
|
||||||
|
cfg.ListOpt('shared_physical_device_mappings', default=[],
|
||||||
|
help=_("Comma-separated list of "
|
||||||
|
"<physical_network>:<network_device> tuples mapping "
|
||||||
|
"physical network names to the agent's node-specific "
|
||||||
|
"shared physical network device between "
|
||||||
|
"SR-IOV and OVS or SR-IOV and linux bridge"))
|
||||||
|
]
|
||||||
|
cfg.CONF.register_opts(fdb_population_opt, 'FDB')
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class FdbPopulationAgentExtension(agent_extension.AgentCoreResourceExtension):
|
||||||
|
"""The FDB population is an agent extension to OVS or linux bridge
|
||||||
|
who's objective is to update the FDB table for existing instance
|
||||||
|
using normal port, thus enabling communication between SR-IOV instances
|
||||||
|
and normal instances.
|
||||||
|
Additional information describing the problem can be found here:
|
||||||
|
http://events.linuxfoundation.org/sites/events/files/slides/LinuxConJapan2014_makita_0.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
# FDB udpates are triggered for ports with a certain device_owner only:
|
||||||
|
# - device owner "compute": updates the FDB with normal port instances,
|
||||||
|
# required in order to enable communication between
|
||||||
|
# SR-IOV direct port instances and normal port instance.
|
||||||
|
# - device owner "router_interface": updates the FDB woth OVS/LB ports,
|
||||||
|
# required in order to enable communication for SR-IOV instances
|
||||||
|
# with floating ip that are located with the network node.
|
||||||
|
# - device owner "DHCP": not required because messages are broadcast.
|
||||||
|
PERMITTED_DEVICE_OWNERS = {'compute', 'network:router_interface'}
|
||||||
|
|
||||||
|
class FdbTableTracker(object):
|
||||||
|
"""FDB table tracker is a helper class
|
||||||
|
intended to keep track of the existing FDB rules.
|
||||||
|
"""
|
||||||
|
def __init__(self, devices):
|
||||||
|
self.device_to_macs = {}
|
||||||
|
self.portid_to_mac = {}
|
||||||
|
# update macs already in the physical interface's FDB table
|
||||||
|
for device in devices:
|
||||||
|
try:
|
||||||
|
_stdout = bridge_lib.FdbInterface.show(device)
|
||||||
|
except RuntimeError as e:
|
||||||
|
LOG.warning(_LW(
|
||||||
|
'Unable to find FDB Interface %(device)s. '
|
||||||
|
'Exception: %(e)s'), {'device': device, 'e': e})
|
||||||
|
continue
|
||||||
|
self.device_to_macs[device] = _stdout.split()[::3]
|
||||||
|
|
||||||
|
def update_port(self, device, port_id, mac):
|
||||||
|
# check if port id is updated
|
||||||
|
if self.portid_to_mac.get(port_id) == mac:
|
||||||
|
return
|
||||||
|
# delete invalid port_id's mac from the FDB,
|
||||||
|
# in case the port was updated to another mac
|
||||||
|
self.delete_port([device], port_id)
|
||||||
|
# update port id
|
||||||
|
self.portid_to_mac[port_id] = mac
|
||||||
|
# check if rule for mac already exists
|
||||||
|
if mac in self.device_to_macs[device]:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
bridge_lib.FdbInterface.add(mac, device)
|
||||||
|
except RuntimeError as e:
|
||||||
|
LOG.warning(_LW(
|
||||||
|
'Unable to add mac %(mac)s '
|
||||||
|
'to FDB Interface %(device)s. '
|
||||||
|
'Exception: %(e)s'),
|
||||||
|
{'mac': mac, 'device': device, 'e': e})
|
||||||
|
return
|
||||||
|
self.device_to_macs[device].append(mac)
|
||||||
|
|
||||||
|
def delete_port(self, devices, port_id):
|
||||||
|
mac = self.portid_to_mac.get(port_id)
|
||||||
|
if mac is None:
|
||||||
|
LOG.warning(_LW('Port Id %(port_id)s does not have a rule for '
|
||||||
|
'devices %(devices)s in FDB table'),
|
||||||
|
{'port_id': port_id, 'devices': devices})
|
||||||
|
return
|
||||||
|
for device in devices:
|
||||||
|
if mac in self.device_to_macs[device]:
|
||||||
|
try:
|
||||||
|
bridge_lib.FdbInterface.delete(mac, device)
|
||||||
|
except RuntimeError as e:
|
||||||
|
LOG.warning(_LW(
|
||||||
|
'Unable to delete mac %(mac)s '
|
||||||
|
'from FDB Interface %(device)s. '
|
||||||
|
'Exception: %(e)s'),
|
||||||
|
{'mac': mac, 'device': device, 'e': e})
|
||||||
|
return
|
||||||
|
self.device_to_macs[device].remove(mac)
|
||||||
|
del self.portid_to_mac[port_id]
|
||||||
|
|
||||||
|
# class FdbPopulationAgentExtension implementation:
|
||||||
|
def initialize(self, connection, driver_type):
|
||||||
|
"""Perform FDB Agent Extension initialization."""
|
||||||
|
valid_driver_types = (linux_bridge_constants.EXTENSION_DRIVER_TYPE,
|
||||||
|
ovs_constants.EXTENSION_DRIVER_TYPE)
|
||||||
|
if driver_type not in valid_driver_types:
|
||||||
|
LOG.error(_LE('FDB extension is only supported for OVS and '
|
||||||
|
'linux bridge agent, currently uses '
|
||||||
|
'%(driver_type)s'), {'driver_type': driver_type})
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
self.device_mappings = n_utils.parse_mappings(
|
||||||
|
cfg.CONF.FDB.shared_physical_device_mappings, unique_keys=False)
|
||||||
|
devices = self._get_devices()
|
||||||
|
if not devices:
|
||||||
|
LOG.error(_LE('Invalid configuration provided for FDB extension: '
|
||||||
|
'no physical devices'))
|
||||||
|
sys.exit(1)
|
||||||
|
self.fdb_tracker = self.FdbTableTracker(devices)
|
||||||
|
|
||||||
|
def handle_port(self, context, details):
|
||||||
|
"""Handle agent FDB population extension for port."""
|
||||||
|
device_owner = details['device_owner']
|
||||||
|
if self._is_valid_device_owner(device_owner):
|
||||||
|
mac = details['mac_address']
|
||||||
|
port_id = details['port_id']
|
||||||
|
physnet = details.get('physical_network')
|
||||||
|
if physnet and physnet in self.device_mappings:
|
||||||
|
for device in self.device_mappings[physnet]:
|
||||||
|
self.fdb_tracker.update_port(device, port_id, mac)
|
||||||
|
|
||||||
|
def delete_port(self, context, details):
|
||||||
|
"""Delete port from FDB population extension."""
|
||||||
|
port_id = details['port_id']
|
||||||
|
devices = self._get_devices()
|
||||||
|
self.fdb_tracker.delete_port(devices, port_id)
|
||||||
|
|
||||||
|
def _get_devices(self):
|
||||||
|
def _flatten_list(l):
|
||||||
|
return [item for sublist in l for item in sublist]
|
||||||
|
|
||||||
|
return _flatten_list(self.device_mappings.values())
|
||||||
|
|
||||||
|
def _is_valid_device_owner(self, device_owner):
|
||||||
|
for permitted_device_owner in self.PERMITTED_DEVICE_OWNERS:
|
||||||
|
if device_owner.startswith(permitted_device_owner):
|
||||||
|
return True
|
||||||
|
return False
|
@ -21,6 +21,7 @@ import os
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
|
from neutron.agent.linux import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -98,3 +99,24 @@ class BridgeDevice(ip_lib.IPDevice):
|
|||||||
return os.listdir(BRIDGE_INTERFACES_FS % self.name)
|
return os.listdir(BRIDGE_INTERFACES_FS % self.name)
|
||||||
except OSError:
|
except OSError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class FdbInterface(object):
|
||||||
|
"""provide basic functionality to edit the FDB table"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add(cls, mac, dev):
|
||||||
|
return utils.execute(['bridge', 'fdb', 'add', mac, 'dev', dev],
|
||||||
|
run_as_root=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, mac, dev):
|
||||||
|
return utils.execute(['bridge', 'fdb', 'delete', mac, 'dev', dev],
|
||||||
|
run_as_root=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def show(cls, dev=None):
|
||||||
|
cmd = ['bridge', 'fdb', 'show']
|
||||||
|
if dev:
|
||||||
|
cmd += ['dev', dev]
|
||||||
|
return utils.execute(cmd, run_as_root=True)
|
||||||
|
176
neutron/tests/unit/agent/l2/extensions/test_fdb_population.py
Normal file
176
neutron/tests/unit/agent/l2/extensions/test_fdb_population.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
# Copyright (c) 2016 Mellanox Technologies, Ltd
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
|
import six
|
||||||
|
|
||||||
|
from neutron.agent.l2.extensions.fdb_population import (
|
||||||
|
FdbPopulationAgentExtension)
|
||||||
|
from neutron.common import utils as n_utils
|
||||||
|
from neutron.plugins.ml2.drivers.linuxbridge.agent.common import (
|
||||||
|
constants as linux_bridge_constants)
|
||||||
|
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
|
||||||
|
constants as ovs_constants)
|
||||||
|
from neutron.tests import base
|
||||||
|
|
||||||
|
|
||||||
|
class FdbPopulationExtensionTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
|
UPDATE_MSG = {u'device_owner': u'network:router_interface',
|
||||||
|
u'physical_network': u'physnet1',
|
||||||
|
u'mac_address': u'fa:16:3e:ba:bc:21',
|
||||||
|
u'port_id': u'17ceda02-43e1-48d8-beb6-35885b20cae6'}
|
||||||
|
DELETE_MSG = {u'port_id': u'17ceda02-43e1-48d8-beb6-35885b20cae6'}
|
||||||
|
FDB_TABLE = ("aa:aa:aa:aa:aa:aa self permanent\n"
|
||||||
|
"bb:bb:bb:bb:bb:bb self permanent")
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(FdbPopulationExtensionTestCase, self).setUp()
|
||||||
|
cfg.CONF.set_override('shared_physical_device_mappings',
|
||||||
|
['physnet1:p1p1'], 'FDB')
|
||||||
|
self.DEVICE = self._get_existing_device()
|
||||||
|
|
||||||
|
def _get_existing_device(self):
|
||||||
|
device_mappings = n_utils.parse_mappings(
|
||||||
|
cfg.CONF.FDB.shared_physical_device_mappings, unique_keys=False)
|
||||||
|
DEVICES = six.next(six.itervalues(device_mappings))
|
||||||
|
return DEVICES[0]
|
||||||
|
|
||||||
|
def _get_fdb_extension(self, mock_execute, fdb_table):
|
||||||
|
mock_execute.return_value = fdb_table
|
||||||
|
fdb_pop = FdbPopulationAgentExtension()
|
||||||
|
fdb_pop.initialize(None, ovs_constants.EXTENSION_DRIVER_TYPE)
|
||||||
|
return fdb_pop
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_initialize(self, mock_execute):
|
||||||
|
fdb_extension = FdbPopulationAgentExtension()
|
||||||
|
fdb_extension.initialize(None, ovs_constants.EXTENSION_DRIVER_TYPE)
|
||||||
|
fdb_extension.initialize(None,
|
||||||
|
linux_bridge_constants.EXTENSION_DRIVER_TYPE)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_initialize_invalid_agent(self, mock_execute):
|
||||||
|
fdb_extension = FdbPopulationAgentExtension()
|
||||||
|
self.assertRaises(SystemExit, fdb_extension.initialize, None, 'sriov')
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_construct_empty_fdb_table(self, mock_execute):
|
||||||
|
self._get_fdb_extension(mock_execute, fdb_table='')
|
||||||
|
cmd = ['bridge', 'fdb', 'show', 'dev', self.DEVICE]
|
||||||
|
mock_execute.assert_called_once_with(cmd, run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_construct_existing_fdb_table(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute,
|
||||||
|
fdb_table=self.FDB_TABLE)
|
||||||
|
cmd = ['bridge', 'fdb', 'show', 'dev', self.DEVICE]
|
||||||
|
mock_execute.assert_called_once_with(cmd, run_as_root=True)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
macs = [line.split()[0] for line in self.FDB_TABLE.split('\n')]
|
||||||
|
for mac in macs:
|
||||||
|
self.assertIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_update_port_add_rule(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, self.FDB_TABLE)
|
||||||
|
mock_execute.reset_mock()
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
cmd = ['bridge', 'fdb', 'add', self.UPDATE_MSG['mac_address'],
|
||||||
|
'dev', self.DEVICE]
|
||||||
|
mock_execute.assert_called_once_with(cmd, run_as_root=True)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
mac = self.UPDATE_MSG['mac_address']
|
||||||
|
self.assertIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_update_port_changed_mac(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, self.FDB_TABLE)
|
||||||
|
mock_execute.reset_mock()
|
||||||
|
mac = self.UPDATE_MSG['mac_address']
|
||||||
|
updated_mac = 'fa:16:3e:ba:bc:33'
|
||||||
|
commands = []
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
commands.append(['bridge', 'fdb', 'add', mac, 'dev', self.DEVICE])
|
||||||
|
self.UPDATE_MSG['mac_address'] = updated_mac
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
commands.append(['bridge', 'fdb', 'delete', mac, 'dev', self.DEVICE])
|
||||||
|
commands.append(['bridge', 'fdb', 'add', updated_mac,
|
||||||
|
'dev', self.DEVICE])
|
||||||
|
calls = []
|
||||||
|
for cmd in commands:
|
||||||
|
calls.append(mock.call(cmd, run_as_root=True))
|
||||||
|
mock_execute.assert_has_calls(calls)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
self.assertIn(updated_mac, updated_macs_for_device)
|
||||||
|
self.assertNotIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_unpermitted_device_owner(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, '')
|
||||||
|
mock_execute.reset_mock()
|
||||||
|
details = copy.deepcopy(self.UPDATE_MSG)
|
||||||
|
details['device_owner'] = 'network:dhcp'
|
||||||
|
fdb_extension.handle_port(context=None, details=details)
|
||||||
|
self.assertFalse(mock_execute.called)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
mac = self.UPDATE_MSG['mac_address']
|
||||||
|
self.assertNotIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_catch_init_exception(self, mock_execute):
|
||||||
|
mock_execute.side_effect = RuntimeError
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, '')
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
self.assertIsNone(updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_catch_update_port_exception(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, '')
|
||||||
|
mock_execute.side_effect = RuntimeError
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
mac = self.UPDATE_MSG['mac_address']
|
||||||
|
self.assertNotIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_catch_delete_port_exception(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, '')
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
mock_execute.side_effect = RuntimeError
|
||||||
|
fdb_extension.delete_port(context=None, details=self.DELETE_MSG)
|
||||||
|
updated_macs_for_device = (
|
||||||
|
fdb_extension.fdb_tracker.device_to_macs.get(self.DEVICE))
|
||||||
|
mac = self.UPDATE_MSG['mac_address']
|
||||||
|
self.assertIn(mac, updated_macs_for_device)
|
||||||
|
|
||||||
|
@mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
def test_delete_port(self, mock_execute):
|
||||||
|
fdb_extension = self._get_fdb_extension(mock_execute, '')
|
||||||
|
fdb_extension.handle_port(context=None, details=self.UPDATE_MSG)
|
||||||
|
mock_execute.reset_mock()
|
||||||
|
fdb_extension.delete_port(context=None, details=self.DELETE_MSG)
|
||||||
|
cmd = ['bridge', 'fdb', 'delete', self.UPDATE_MSG['mac_address'],
|
||||||
|
'dev', self.DEVICE]
|
||||||
|
mock_execute.assert_called_once_with(cmd, run_as_root=True)
|
17
releasenotes/notes/fdb_population-70d751c8c2e4395f.yaml
Normal file
17
releasenotes/notes/fdb_population-70d751c8c2e4395f.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- In order to fix the communication issues between
|
||||||
|
SR-IOV instances and regular instances
|
||||||
|
the FDB population extension is added to the
|
||||||
|
OVS or linuxbridge agent.
|
||||||
|
the cause was that messages from SR-IOV direct port
|
||||||
|
instance to normal port instances located on
|
||||||
|
the same hypervisor were sent directly to the wire
|
||||||
|
because the FDB table was not yet updated.
|
||||||
|
FDB population extension tracks instances
|
||||||
|
boot/delete operations using the handle_port
|
||||||
|
delete_port extension interface messages
|
||||||
|
and update the hypervisor's FDB table accordingly.
|
||||||
|
|
||||||
|
Please note this L2 agent extension doesn't support
|
||||||
|
allowed address pairs extension.
|
@ -111,6 +111,7 @@ neutron.ipam_drivers =
|
|||||||
internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool
|
internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool
|
||||||
neutron.agent.l2.extensions =
|
neutron.agent.l2.extensions =
|
||||||
qos = neutron.agent.l2.extensions.qos:QosAgentExtension
|
qos = neutron.agent.l2.extensions.qos:QosAgentExtension
|
||||||
|
fdb = neutron.agent.l2.extensions.fdb_population:FdbPopulationAgentExtension
|
||||||
neutron.qos.agent_drivers =
|
neutron.qos.agent_drivers =
|
||||||
ovs = neutron.plugins.ml2.drivers.openvswitch.agent.extension_drivers.qos_driver:QosOVSAgentDriver
|
ovs = neutron.plugins.ml2.drivers.openvswitch.agent.extension_drivers.qos_driver:QosOVSAgentDriver
|
||||||
sriov = neutron.plugins.ml2.drivers.mech_sriov.agent.extension_drivers.qos_driver:QosSRIOVAgentDriver
|
sriov = neutron.plugins.ml2.drivers.mech_sriov.agent.extension_drivers.qos_driver:QosSRIOVAgentDriver
|
||||||
|
Loading…
Reference in New Issue
Block a user