diff --git a/doc/source/admin/ovn/routing.rst b/doc/source/admin/ovn/routing.rst index 629f820949d..9d5caa6d761 100644 --- a/doc/source/admin/ovn/routing.rst +++ b/doc/source/admin/ovn/routing.rst @@ -20,6 +20,21 @@ traffic, and also for FIPs. :alt: L3 North South non-distributed FIP :align: center +When an external network connected to the router is represented by FLAT or +VLAN network type, active chassis is identified by the external Logical Router +Port. In practice this means, that LRP will have ``hosting-chassis`` property +set in a ``status`` row for the external LRP. You can also check Chassis +priorities for the LRP with ``lrp-get-gateway-chassis`` command. Changing the +priority will result in traffic failover to another Chassis. + +In case of connecting another Geneve network to the router as external network +(by creating ``access_as_external`` RBAC rule for such network), router itself +will be pinned to Chassis rather than it's LRP. In this scenario Logical Router +does have ``chassis`` property defined inside the ``options`` row. +With that ``GATEWAY_PORT`` will not be defined for dnat_and_snat rules which +are created for FIPs as this will make traffic to pass through the LRP that +is not bound to any Chassis. + Distributed Floating IP ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py index eef9ee22574..c062ce9a8ae 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py @@ -931,12 +931,17 @@ class OVNClient: 'external_ids': ext_ids} # If OVN supports gateway_port column for NAT rules set gateway port - # uuid to any floating IP without gw port reference - LP#2035281. + # uuid to floating IP without gw port reference - LP#2035281. if utils.is_nat_gateway_port_supported(self._nb_idl): router_db = self._l3_plugin.get_router(admin_context, router_id) gw_port_id = router_db.get('gw_port_id') lrp = self._nb_idl.get_lrouter_port(gw_port_id) - columns['gateway_port'] = lrp.uuid + # If LRP is not bound to a chassis, it means that router can be + # bound instead. In this case we do not want to define + # gateway_port LP#2083527. + if lrp.options.get( + ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH) == 'true': + columns['gateway_port'] = lrp.uuid if ovn_conf.is_ovn_distributed_floating_ip(): if self._nb_idl.lsp_get_up(floatingip['port_id']).execute(): diff --git a/neutron/tests/unit/services/ovn_l3/test_plugin.py b/neutron/tests/unit/services/ovn_l3/test_plugin.py index f46ca57f6fc..cfc3ecdf638 100644 --- a/neutron/tests/unit/services/ovn_l3/test_plugin.py +++ b/neutron/tests/unit/services/ovn_l3/test_plugin.py @@ -1389,9 +1389,11 @@ class BaseTestOVNL3RouterPluginMixin(): {'external_ip': '192.168.0.10', 'logical_ip': '10.0.0.0/24', 'type': 'snat', 'uuid': 'uuid1'}] utils.is_nat_gateway_port_supported.return_value = is_gw_port - + lrp_options = {} + if is_gw_port: + lrp_options[ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH] = 'true' lrp = fake_resources.FakeOvsdbRow.create_one_ovsdb_row( - attrs={'options': {}}) + attrs={'options': lrp_options}) _nb_ovn.get_lrouter_port.return_value = lrp self.l3_inst.get_router.return_value = self.fake_router_with_ext_gw