Skip to content

Commit 0dd3cf9

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "[OVN] Warn about invalid OVN and FIP PF config during start of Neutron" into stable/2023.1
2 parents c019a42 + c40f637 commit 0dd3cf9

File tree

8 files changed

+190
-12
lines changed

8 files changed

+190
-12
lines changed

neutron/cmd/upgrade_checks/checks.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727

2828
from neutron._i18n import _
2929
from neutron.cmd.upgrade_checks import base
30+
from neutron.common.ovn import exceptions as ovn_exc
31+
from neutron.common.ovn import utils as ovn_utils
32+
from neutron.conf.plugins.ml2 import config as ml2_conf
33+
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
3034
from neutron.conf import service as conf_service
3135
from neutron.db.extra_dhcp_opt import models as extra_dhcp_opt_models
3236
from neutron.db.models import agent as agent_model
@@ -179,6 +183,8 @@ def get_checks(self):
179183
self.floatingip_inherit_qos_from_network),
180184
(_('Port extra DHCP options check'),
181185
self.extra_dhcp_options_check),
186+
(_('Floating IP Port forwarding and OVN L3 plugin configuration'),
187+
self.ovn_port_forwarding_configuration_check),
182188
]
183189

184190
@staticmethod
@@ -515,3 +521,28 @@ def extra_dhcp_options_check(checker):
515521
upgradecheck.Code.SUCCESS,
516522
_('There are no extra_dhcp_opts with the newline character '
517523
'in the option name or option value.'))
524+
525+
@staticmethod
526+
def ovn_port_forwarding_configuration_check(checker):
527+
ovn_l3_plugin_names = [
528+
'ovn-router',
529+
'neutron.services.ovn_l3.plugin.OVNL3RouterPlugin']
530+
if not any(plugin in ovn_l3_plugin_names
531+
for plugin in cfg.CONF.service_plugins):
532+
return upgradecheck.Result(
533+
upgradecheck.Code.SUCCESS, _('No OVN L3 plugin enabled.'))
534+
535+
ml2_conf.register_ml2_plugin_opts()
536+
ovn_conf.register_opts()
537+
try:
538+
ovn_utils.validate_port_forwarding_configuration()
539+
return upgradecheck.Result(
540+
upgradecheck.Code.SUCCESS,
541+
_('OVN L3 plugin and Port Forwarding configuration are fine.'))
542+
except ovn_exc.InvalidPortForwardingConfiguration:
543+
return upgradecheck.Result(
544+
upgradecheck.Code.WARNING,
545+
_('Neutron configuration is invalid. Port forwardings '
546+
'can not be used with ML2/OVN backend, distributed '
547+
'floating IPs and provider network type(s) used as '
548+
'tenant networks.'))

neutron/common/ovn/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,10 @@ class HashRingIsEmpty(n_exc.NeutronException):
3737
'%(node_count)d nodes were found offline. This should never '
3838
'happen in a normal situation, please check the status '
3939
'of your cluster')
40+
41+
42+
class InvalidPortForwardingConfiguration(n_exc.NeutronException):
43+
message = _('Neutron configuration is invalid. Port forwardings '
44+
'can not be used with ML2/OVN backend, distributed '
45+
'floating IPs and provider network type(s) used as '
46+
'tenant networks.')

neutron/common/ovn/utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,3 +1211,20 @@ def get_requested_chassis(requested_chassis):
12111211
# becomes the norm and older versions of OVN are no longer supported
12121212
def is_additional_chassis_supported(idl):
12131213
return idl.is_col_present('Port_Binding', 'additional_chassis')
1214+
1215+
1216+
def validate_port_forwarding_configuration():
1217+
if not ovn_conf.is_ovn_distributed_floating_ip():
1218+
return
1219+
1220+
pf_plugin_names = [
1221+
'port_forwarding',
1222+
'neutron.services.portforwarding.pf_plugin.PortForwardingPlugin']
1223+
if not any(plugin in pf_plugin_names
1224+
for plugin in cfg.CONF.service_plugins):
1225+
return
1226+
1227+
provider_network_types = ['vlan', 'flat']
1228+
if any(net_type in provider_network_types
1229+
for net_type in cfg.CONF.ml2.tenant_network_types):
1230+
raise ovn_exc.InvalidPortForwardingConfiguration()

neutron/services/portforwarding/drivers/ovn/driver.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@
1010
# License for the specific language governing permissions and limitations
1111
# under the License.
1212

13-
from oslo_log import log
14-
15-
from ovsdbapp.backend.ovs_idl import idlutils
16-
from ovsdbapp import constants as ovsdbapp_const
17-
1813
from neutron_lib.callbacks import events
1914
from neutron_lib.callbacks import registry
2015
from neutron_lib.callbacks import resources
2116
from neutron_lib import constants as const
2217
from neutron_lib.plugins import constants as plugin_constants
2318
from neutron_lib.plugins import directory
19+
from oslo_log import log
20+
from ovsdbapp.backend.ovs_idl import idlutils
21+
from ovsdbapp import constants as ovsdbapp_const
2422

2523
from neutron.common.ovn import constants as ovn_const
24+
from neutron.common.ovn import exceptions as ovn_exc
2625
from neutron.common.ovn import utils as ovn_utils
2726
from neutron.db import ovn_revision_numbers_db as db_rev
2827
from neutron import manager
@@ -192,10 +191,27 @@ def port_forwarding_deleted(self, ovn_txn, nb_ovn, pf_obj):
192191
class OVNPortForwarding(object):
193192

194193
def __init__(self, l3_plugin):
194+
self._validate_configuration()
195195
self._l3_plugin = l3_plugin
196196
self._pf_plugin_property = None
197197
self._handler = OVNPortForwardingHandler()
198198

199+
def _validate_configuration(self):
200+
"""This method checks if Neutron config is compatible with OVN and PFs.
201+
202+
It stops process in case when provider network types (vlan/flat)
203+
are enabled as tenant networks AND distributed floating IPs are enabled
204+
as this configuration is not working fine with FIP PFs in ML2/OVN case.
205+
"""
206+
try:
207+
ovn_utils.validate_port_forwarding_configuration()
208+
except ovn_exc.InvalidPortForwardingConfiguration:
209+
LOG.warning("Neutron configuration is invalid for port "
210+
"forwardings and ML2/OVN backend. "
211+
"It is not valid to use together provider network "
212+
"types (vlan/flat) as tenant networks, distributed "
213+
"floating IPs and port forwardings.")
214+
199215
@property
200216
def _pf_plugin(self):
201217
if self._pf_plugin_property is None:

neutron/tests/unit/cmd/upgrade_checks/test_checks.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from oslo_upgradecheck.upgradecheck import Code
1919

2020
from neutron.cmd.upgrade_checks import checks
21+
from neutron.common.ovn import exceptions as ovn_exc
22+
from neutron.common.ovn import utils as ovn_utils
2123
from neutron.tests import base
2224

2325

@@ -278,3 +280,25 @@ def test_extra_dhcp_options_check_bad_value(self):
278280
opt_value='bar\nbar')]
279281
result = checks.CoreChecks.extra_dhcp_options_check(mock.ANY)
280282
self.assertEqual(Code.WARNING, result.code)
283+
284+
def test_ovn_port_forwarding_configuration_check_ovn_l3_success(self):
285+
cfg.CONF.set_override("service_plugins", 'ovn-router')
286+
with mock.patch.object(
287+
ovn_utils,
288+
'validate_port_forwarding_configuration') as validate_mock:
289+
result = checks.CoreChecks.ovn_port_forwarding_configuration_check(
290+
mock.ANY)
291+
self.assertEqual(Code.SUCCESS, result.code)
292+
validate_mock.assert_called_once_with()
293+
294+
def test_ovn_port_forwarding_configuration_check_ovn_l3_failure(self):
295+
cfg.CONF.set_override("service_plugins", 'ovn-router')
296+
with mock.patch.object(
297+
ovn_utils,
298+
'validate_port_forwarding_configuration',
299+
side_effect=ovn_exc.InvalidPortForwardingConfiguration
300+
) as validate_mock:
301+
result = checks.CoreChecks.ovn_port_forwarding_configuration_check(
302+
mock.ANY)
303+
self.assertEqual(Code.WARNING, result.code)
304+
validate_mock.assert_called_once_with()

neutron/tests/unit/common/ovn/test_utils.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import testtools
3030

3131
from neutron.common.ovn import constants
32+
from neutron.common.ovn import exceptions as ovn_exc
3233
from neutron.common.ovn import utils
3334
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
3435
from neutron.tests import base
@@ -1172,3 +1173,44 @@ def test_vnic_remote_managed_port_context(self):
11721173
self.fake_smartnic_hostname,
11731174
utils.determine_bind_host(self.mock_sb_idl, {},
11741175
port_context=context))
1176+
1177+
1178+
class ValidatePortForwardingConfigurationTestCase(base.BaseTestCase):
1179+
1180+
def setUp(self):
1181+
super().setUp()
1182+
ovn_conf.register_opts()
1183+
1184+
def test_validation_when_distributed_fip_disabled(self):
1185+
cfg.CONF.set_override(
1186+
'enable_distributed_floating_ip', False, group='ovn')
1187+
cfg.CONF.set_override('service_plugins', 'some_plugin,port_forwarding')
1188+
cfg.CONF.set_override('tenant_network_types', 'geneve,vlan',
1189+
group='ml2')
1190+
utils.validate_port_forwarding_configuration()
1191+
1192+
def test_validation_when_no_pf_plugin_enabled(self):
1193+
cfg.CONF.set_override(
1194+
'enable_distributed_floating_ip', True, group='ovn')
1195+
cfg.CONF.set_override('service_plugins', 'some_plugin')
1196+
cfg.CONF.set_override('tenant_network_types', 'geneve,vlan',
1197+
group='ml2')
1198+
utils.validate_port_forwarding_configuration()
1199+
1200+
def test_validation_when_no_provider_net_configured(self):
1201+
cfg.CONF.set_override(
1202+
'enable_distributed_floating_ip', True, group='ovn')
1203+
cfg.CONF.set_override('service_plugins', 'some_plugin,port_forwarding')
1204+
cfg.CONF.set_override('tenant_network_types', 'geneve,vxlan',
1205+
group='ml2')
1206+
utils.validate_port_forwarding_configuration()
1207+
1208+
def test_validation_when_pf_and_provider_net_enabled(self):
1209+
cfg.CONF.set_override(
1210+
'enable_distributed_floating_ip', True, group='ovn')
1211+
cfg.CONF.set_override('service_plugins', 'some_plugin,port_forwarding')
1212+
cfg.CONF.set_override('tenant_network_types', 'geneve,vlan',
1213+
group='ml2')
1214+
self.assertRaises(
1215+
ovn_exc.InvalidPortForwardingConfiguration,
1216+
utils.validate_port_forwarding_configuration)

neutron/tests/unit/services/portforwarding/drivers/ovn/test_driver.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,25 @@
1414

1515
from unittest import mock
1616

17+
from neutron_lib.callbacks import events
18+
from neutron_lib.callbacks import registry
19+
from neutron_lib.callbacks import resources
20+
from neutron_lib import constants as const
21+
from neutron_lib.plugins import constants as plugin_constants
22+
from oslo_utils import uuidutils
23+
from ovsdbapp import constants as ovsdbapp_const
24+
1725
from neutron.common.ovn import constants as ovn_const
26+
from neutron.common.ovn import exceptions as ovn_exc
27+
from neutron.common.ovn import utils as ovn_utils
28+
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
1829
from neutron.objects import port_forwarding as port_forwarding_obj
1930
from neutron.services.portforwarding.constants import PORT_FORWARDING
2031
from neutron.services.portforwarding.constants import PORT_FORWARDING_PLUGIN
2132
from neutron.services.portforwarding.drivers.ovn import driver \
2233
as port_forwarding
2334
from neutron.tests import base
2435
from neutron.tests.unit import fake_resources
25-
from neutron_lib.callbacks import events
26-
from neutron_lib.callbacks import registry
27-
from neutron_lib.callbacks import resources
28-
from neutron_lib import constants as const
29-
from neutron_lib.plugins import constants as plugin_constants
30-
from oslo_utils import uuidutils
31-
from ovsdbapp import constants as ovsdbapp_const
3236

3337

3438
class TestOVNPortForwardingBase(base.BaseTestCase):
@@ -450,6 +454,7 @@ def test_port_forwarding_deleted(self, m_info):
450454
class TestOVNPortForwarding(TestOVNPortForwardingBase):
451455
def setUp(self):
452456
super(TestOVNPortForwarding, self).setUp()
457+
ovn_conf.register_opts()
453458
self.pf_plugin = mock.Mock()
454459
self.handler = mock.Mock()
455460
get_mock_pf_plugin = lambda alias: self.pf_plugin if (
@@ -475,6 +480,25 @@ def test_init(self):
475480
self.assertEqual(self._ovn_pf._handler, self.handler)
476481
self.assertEqual(self._ovn_pf._pf_plugin, self.pf_plugin)
477482

483+
def test__validate_configuration_ok(self):
484+
with mock.patch.object(
485+
port_forwarding.LOG, "warning") as mock_warning, \
486+
mock.patch.object(ovn_utils,
487+
"validate_port_forwarding_configuration"):
488+
489+
self._ovn_pf._validate_configuration()
490+
mock_warning.assert_not_called()
491+
492+
def test__validate_configuration_wrong(self):
493+
with mock.patch.object(
494+
port_forwarding.LOG, "warning") as mock_warning, \
495+
mock.patch.object(
496+
ovn_utils,
497+
"validate_port_forwarding_configuration",
498+
side_effect=ovn_exc.InvalidPortForwardingConfiguration):
499+
self._ovn_pf._validate_configuration()
500+
mock_warning.assert_called_once_with(mock.ANY)
501+
478502
def test_register(self):
479503
with mock.patch.object(registry, 'subscribe') as mock_subscribe:
480504
self._ovn_pf.register(mock.ANY, mock.ANY, mock.Mock())
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
other:
3+
- |
4+
When the following configuration is enabled at the same time:
5+
6+
* OVN L3 service plugin (``ovn-router``)
7+
* Port forwarding service plugin (``port_forwarding``)
8+
* "vlan" or "flat" network types configured in the ML2 configuration
9+
variable ``tenant_network_types``
10+
* The OVN floating IP traffic is distributed
11+
(``enable_distributed_floating_ip`` = ``True``)
12+
13+
the Neutron server will report a warning during plugin initialization
14+
because this is an invalid configuration matrix. Floating IPs need to
15+
always be centralized in such a case.
16+
For more details see `bug report
17+
<https://bugs.launchpad.net/neutron/+bug/2028846>`_.

0 commit comments

Comments
 (0)