nb driver: Don't expose FIP if the external_mac is not set
If the external_mac in the NAT entry is not set then it means two things: 1) The DVR is disabled (see [2]) 2) The external_mac has not been set yet because Neutron doesn't populate the external_mac column of the FIP NAT entry until the associated port with the FIP is bound to a chassis. This is because of LB VIPs that don't get bound [1]. For case 1) we need to expose the FIP on the gateway node where the LRP is hosted. For case 2) we can ignore if the external_mac is not set but then we need another event that would re-act on setting the external_mac. This will be done in a followup patch. [1] https://bugs.launchpad.net/networking-ovn/+bug/1789686 [2] https://bugs.launchpad.net/ovn-bgp-agent/+bug/2056477 Related-Bug: #2073403 Change-Id: Ie24f1f370c44f95840af2d4d2010c20655738ebc Signed-off-by: Jakub Libosvar <libosvar@redhat.com>
This commit is contained in:
17
ovn_bgp_agent/drivers/openstack/nb_exceptions.py
Normal file
17
ovn_bgp_agent/drivers/openstack/nb_exceptions.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright 2024 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
class NATNotFound(Exception):
|
||||||
|
pass
|
@@ -22,6 +22,7 @@ from oslo_log import log as logging
|
|||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
from ovn_bgp_agent.drivers import driver_api
|
from ovn_bgp_agent.drivers import driver_api
|
||||||
|
from ovn_bgp_agent.drivers.openstack import nb_exceptions
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import ovn
|
from ovn_bgp_agent.drivers.openstack.utils import ovn
|
||||||
@@ -231,9 +232,12 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
|||||||
def _ensure_lsp_exposed(self, port):
|
def _ensure_lsp_exposed(self, port):
|
||||||
port_fip = port.external_ids.get(constants.OVN_FIP_EXT_ID_KEY)
|
port_fip = port.external_ids.get(constants.OVN_FIP_EXT_ID_KEY)
|
||||||
if port_fip:
|
if port_fip:
|
||||||
external_ip, external_mac, ls_name = (
|
try:
|
||||||
self.get_port_external_ip_and_ls(port.name))
|
external_ip, external_mac, ls_name = (
|
||||||
if not external_ip or not ls_name:
|
self.get_port_external_ip_and_ls(port.name))
|
||||||
|
except nb_exceptions.NATNotFound as e:
|
||||||
|
LOG.debug("Logical Switch Port %s does not have all data "
|
||||||
|
"required in its NAT entry: %s", port.name, e)
|
||||||
return
|
return
|
||||||
return self._expose_fip(external_ip, external_mac, ls_name, port)
|
return self._expose_fip(external_ip, external_mac, ls_name, port)
|
||||||
|
|
||||||
@@ -551,14 +555,26 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
|||||||
|
|
||||||
def get_port_external_ip_and_ls(self, port):
|
def get_port_external_ip_and_ls(self, port):
|
||||||
nat_entry = self.nb_idl.get_nat_by_logical_port(port)
|
nat_entry = self.nb_idl.get_nat_by_logical_port(port)
|
||||||
if not nat_entry:
|
try:
|
||||||
return None, None, None
|
net_id = nat_entry.external_ids[constants.OVN_FIP_NET_EXT_ID_KEY]
|
||||||
net_id = nat_entry.external_ids.get(constants.OVN_FIP_NET_EXT_ID_KEY)
|
except AttributeError:
|
||||||
if not net_id:
|
# nat_entry is None and has no external_ids attribute
|
||||||
return nat_entry.external_ip, nat_entry.external_mac[0], None
|
raise nb_exceptions.NATNotFound(
|
||||||
else:
|
"NAT entry for port %s not found" % port)
|
||||||
ls_name = "neutron-{}".format(net_id)
|
except KeyError:
|
||||||
return nat_entry.external_ip, nat_entry.external_mac[0], ls_name
|
# network ID was not found in the NAT entry
|
||||||
|
raise nb_exceptions.NATNotFound(
|
||||||
|
"NAT entry for port %s does not contain network ID in its "
|
||||||
|
"external_ids" % port)
|
||||||
|
try:
|
||||||
|
external_mac = nat_entry.external_mac[0]
|
||||||
|
except IndexError:
|
||||||
|
raise nb_exceptions.NATNotFound(
|
||||||
|
"NAT entry for port %s does not have external_mac set" % (
|
||||||
|
port))
|
||||||
|
|
||||||
|
ls_name = "neutron-{}".format(net_id)
|
||||||
|
return nat_entry.external_ip, external_mac, ls_name
|
||||||
|
|
||||||
@lockutils.synchronized('nbbgp')
|
@lockutils.synchronized('nbbgp')
|
||||||
def expose_fip(self, ip, mac, logical_switch, row):
|
def expose_fip(self, ip, mac, logical_switch, row):
|
||||||
@@ -1052,11 +1068,12 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
|||||||
LOG.debug("Something went wrong, VIP port %s not found", vip_port)
|
LOG.debug("Something went wrong, VIP port %s not found", vip_port)
|
||||||
return
|
return
|
||||||
|
|
||||||
external_ip, external_mac, ls_name = (
|
try:
|
||||||
self.get_port_external_ip_and_ls(vip_lsp.name))
|
external_ip, external_mac, ls_name = (
|
||||||
if not external_ip or not ls_name:
|
self.get_port_external_ip_and_ls(vip_lsp.name))
|
||||||
LOG.debug("Something went wrong, no NAT entry for the VIP %s",
|
except nb_exceptions.NATNotFound as e:
|
||||||
vip_port)
|
LOG.debug("Something went wrong with the VIP %s: %s",
|
||||||
|
vip_port, e)
|
||||||
return
|
return
|
||||||
self._expose_fip(external_ip, external_mac, ls_name, vip_lsp)
|
self._expose_fip(external_ip, external_mac, ls_name, vip_lsp)
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@ from oslo_concurrency import lockutils
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
|
from ovn_bgp_agent.drivers.openstack import nb_exceptions
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import common as common_utils
|
from ovn_bgp_agent.drivers.openstack.utils import common as common_utils
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import loadbalancer as lb_utils
|
from ovn_bgp_agent.drivers.openstack.utils import loadbalancer as lb_utils
|
||||||
@@ -235,9 +236,12 @@ class LogicalSwitchPortFIPCreateEvent(base_watcher.LSPChassisEvent):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _run(self, event, row, old):
|
def _run(self, event, row, old):
|
||||||
external_ip, external_mac, ls_name = (
|
try:
|
||||||
self.agent.get_port_external_ip_and_ls(row.name))
|
external_ip, external_mac, ls_name = (
|
||||||
if not external_ip or not ls_name:
|
self.agent.get_port_external_ip_and_ls(row.name))
|
||||||
|
except nb_exceptions.NATNotFound as e:
|
||||||
|
LOG.debug("Logical Switch Port %s does not have all data required"
|
||||||
|
" in its NAT entry: %s", row.name, e)
|
||||||
return
|
return
|
||||||
|
|
||||||
with _SYNC_STATE_LOCK.read_lock():
|
with _SYNC_STATE_LOCK.read_lock():
|
||||||
|
@@ -18,6 +18,7 @@ from unittest import mock
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
|
from ovn_bgp_agent.drivers.openstack import nb_exceptions
|
||||||
from ovn_bgp_agent.drivers.openstack import nb_ovn_bgp_driver
|
from ovn_bgp_agent.drivers.openstack import nb_ovn_bgp_driver
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
||||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||||
@@ -740,9 +741,9 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
|||||||
def test_get_port_external_ip_and_ls_no_nat_entry(self):
|
def test_get_port_external_ip_and_ls_no_nat_entry(self):
|
||||||
self.nb_idl.get_nat_by_logical_port.return_value = None
|
self.nb_idl.get_nat_by_logical_port.return_value = None
|
||||||
|
|
||||||
ret = self.nb_bgp_driver.get_port_external_ip_and_ls('fake-port')
|
self.assertRaises(
|
||||||
|
nb_exceptions.NATNotFound,
|
||||||
self.assertEqual(ret, (None, None, None))
|
self.nb_bgp_driver.get_port_external_ip_and_ls, 'fake-port')
|
||||||
|
|
||||||
def test_get_port_external_ip_and_ls_no_external_id(self):
|
def test_get_port_external_ip_and_ls_no_external_id(self):
|
||||||
nat_entry = fakes.create_object({
|
nat_entry = fakes.create_object({
|
||||||
@@ -751,10 +752,9 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
|||||||
'external_mac': ['fake-mac']})
|
'external_mac': ['fake-mac']})
|
||||||
self.nb_idl.get_nat_by_logical_port.return_value = nat_entry
|
self.nb_idl.get_nat_by_logical_port.return_value = nat_entry
|
||||||
|
|
||||||
ret = self.nb_bgp_driver.get_port_external_ip_and_ls('fake-port')
|
self.assertRaises(
|
||||||
|
nb_exceptions.NATNotFound,
|
||||||
self.assertEqual(
|
self.nb_bgp_driver.get_port_external_ip_and_ls, 'fake-port')
|
||||||
ret, (nat_entry.external_ip, nat_entry.external_mac[0], None))
|
|
||||||
|
|
||||||
def test_expose_fip(self):
|
def test_expose_fip(self):
|
||||||
ip = '10.0.0.1'
|
ip = '10.0.0.1'
|
||||||
@@ -1706,9 +1706,9 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
|||||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'
|
constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'
|
||||||
})
|
})
|
||||||
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
||||||
mock_get_port_external_ip_and_ls = mock.patch.object(
|
mock.patch.object(
|
||||||
self.nb_bgp_driver, 'get_port_external_ip_and_ls').start()
|
self.nb_bgp_driver, 'get_port_external_ip_and_ls',
|
||||||
mock_get_port_external_ip_and_ls.return_value = (None, None, None)
|
side_effect=nb_exceptions.NATNotFound).start()
|
||||||
mock_expose_fip = mock.patch.object(
|
mock_expose_fip = mock.patch.object(
|
||||||
self.nb_bgp_driver, '_expose_fip').start()
|
self.nb_bgp_driver, '_expose_fip').start()
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
|
from ovn_bgp_agent.drivers.openstack import nb_exceptions
|
||||||
from ovn_bgp_agent.drivers.openstack.watchers import nb_bgp_watcher
|
from ovn_bgp_agent.drivers.openstack.watchers import nb_bgp_watcher
|
||||||
from ovn_bgp_agent.tests import base as test_base
|
from ovn_bgp_agent.tests import base as test_base
|
||||||
from ovn_bgp_agent.tests import utils
|
from ovn_bgp_agent.tests import utils
|
||||||
@@ -420,15 +421,13 @@ class TestLogicalSwitchPortFIPCreateEvent(test_base.TestCase):
|
|||||||
ls_name, row)
|
ls_name, row)
|
||||||
|
|
||||||
def test_run_no_external_ip(self):
|
def test_run_no_external_ip(self):
|
||||||
external_ip = None
|
self.agent.get_port_external_ip_and_ls.side_effect = (
|
||||||
ls_name = 'logical_switch'
|
nb_exceptions.NATNotFound)
|
||||||
self.agent.get_port_external_ip_and_ls.return_value = (external_ip,
|
|
||||||
'mac',
|
|
||||||
ls_name)
|
|
||||||
row = utils.create_row(type=constants.OVN_VM_VIF_PORT_TYPE,
|
row = utils.create_row(type=constants.OVN_VM_VIF_PORT_TYPE,
|
||||||
addresses=['mac 192.168.0.1'],
|
addresses=['mac 192.168.0.1'],
|
||||||
name='net-id')
|
name='net-id')
|
||||||
self.event.run(mock.Mock(), row, mock.Mock())
|
self.event.run(mock.ANY, row, mock.ANY)
|
||||||
self.agent.expose_fip.assert_not_called()
|
self.agent.expose_fip.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user