Allow to create ovn loadbalancer on dual-stack provider networks

This patch ensures that loadbalancer can be created with the VIP
on the provider networks when they are dual-stack (ipv4 and ipv6
subnets).

Closes-Bug: #1959903
Change-Id: Ic0e6c02defb5c98791a3c3d99ff2b7cfc0ccfe2e
This commit is contained in:
Luis Tomas Bolivar 2022-02-03 14:48:39 +01:00
parent a4ec59288a
commit 1ac25e8814
3 changed files with 25 additions and 12 deletions

View File

@ -28,6 +28,7 @@ OVN_DEVICE_OWNER_EXT_ID_KEY = 'neutron:device_owner'
OVN_FIP_EXT_ID_KEY = 'neutron:fip_id' OVN_FIP_EXT_ID_KEY = 'neutron:fip_id'
OVN_FIP_PORT_EXT_ID_KEY = 'neutron:fip_port_id' OVN_FIP_PORT_EXT_ID_KEY = 'neutron:fip_port_id'
OVN_GW_PORT_EXT_ID_KEY = 'neutron:gw_port_id' OVN_GW_PORT_EXT_ID_KEY = 'neutron:gw_port_id'
OVN_PORT_CIDR_EXT_ID_KEY = 'neutron:cidrs'
LB_EXT_IDS_LS_REFS_KEY = 'ls_refs' LB_EXT_IDS_LS_REFS_KEY = 'ls_refs'
LB_EXT_IDS_LR_REF_KEY = 'lr_ref' LB_EXT_IDS_LR_REF_KEY = 'lr_ref'

View File

@ -634,10 +634,14 @@ class OvnProviderHelper():
def _find_lr_of_ls(self, ovn_ls, subnet_gateway_ip=None): def _find_lr_of_ls(self, ovn_ls, subnet_gateway_ip=None):
lsp_router_port = None lsp_router_port = None
for port in ovn_ls.ports or []: for port in ovn_ls.ports or []:
if port.type == 'router': if (port.type == 'router' and
port.external_ids.get(
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY) ==
n_const.DEVICE_OWNER_ROUTER_INTF):
if subnet_gateway_ip: if subnet_gateway_ip:
port_cidr = netaddr.IPNetwork( port_cidr = netaddr.IPNetwork(
port.external_ids['neutron:cidrs']).ip port.external_ids[
ovn_const.OVN_PORT_CIDR_EXT_ID_KEY]).ip
if netaddr.IPAddress(subnet_gateway_ip) != port_cidr: if netaddr.IPAddress(subnet_gateway_ip) != port_cidr:
continue continue
lsp_router_port = port lsp_router_port = port
@ -1533,9 +1537,8 @@ class OvnProviderHelper():
ovn_lr = self._find_lr_of_ls( ovn_lr = self._find_lr_of_ls(
ovn_ls, subnet['subnet'].get('gateway_ip')) ovn_ls, subnet['subnet'].get('gateway_ip'))
if ovn_lr: if ovn_lr:
for net in self._find_ls_for_lr(ovn_lr): commands.extend(self._update_lb_to_lr_association(
commands.append(self.ovn_nbdb_api.ls_lb_add( ovn_lb, ovn_lr))
net, ovn_lb.uuid, may_exist=True))
except n_exc.NotFound: except n_exc.NotFound:
pass pass
except idlutils.RowNotFound: except idlutils.RowNotFound:

View File

@ -14,6 +14,7 @@
import copy import copy
from unittest import mock from unittest import mock
from neutron_lib import constants as n_const
from neutronclient.common import exceptions as n_exc from neutronclient.common import exceptions as n_exc
from octavia_lib.api.drivers import data_models from octavia_lib.api.drivers import data_models
from octavia_lib.api.drivers import exceptions from octavia_lib.api.drivers import exceptions
@ -1215,20 +1216,22 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
self.assertEqual(status['members'][0]['operating_status'], self.assertEqual(status['members'][0]['operating_status'],
constants.OFFLINE) constants.OFFLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr') @mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls') @mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client') @mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create_lb_add_from_lr(self, net_cli, f_lr, f_ls): def test_member_create_lb_add_from_lr(self, net_cli, f_lr, folbpi):
fake_subnet = fakes.FakeSubnet.create_one_subnet() fake_subnet = fakes.FakeSubnet.create_one_subnet()
net_cli.return_value.show_subnet.return_value = {'subnet': fake_subnet} net_cli.return_value.show_subnet.return_value = {'subnet': fake_subnet}
f_lr.return_value = self.router f_lr.return_value = self.router
f_ls.return_value = [self.network] pool_key = 'pool_%s' % self.pool_id
folbpi.return_value = (pool_key, self.ovn_lb)
self.ovn_lb.external_ids = mock.MagicMock() self.ovn_lb.external_ids = mock.MagicMock()
status = self.helper.member_create(self.member) status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'], self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE) constants.ACTIVE)
f_lr.assert_called_once_with(self.network, fake_subnet['gateway_ip']) f_lr.assert_called_once_with(self.network, fake_subnet['gateway_ip'])
f_ls.assert_called_once_with(self.router) self.helper._update_lb_to_lr_association.assert_called_once_with(
self.ovn_lb, self.router)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr') @mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls') @mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@ -1832,7 +1835,9 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
attrs={ attrs={
'external_ids': { 'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1', ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
'neutron:cidrs': '10.10.10.1/24'}, 'neutron:cidrs': '10.10.10.1/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router', 'type': 'router',
'options': { 'options': {
'router-port': 'lrp-foo-name'}, 'router-port': 'lrp-foo-name'},
@ -1841,7 +1846,9 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
attrs={ attrs={
'external_ids': { 'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router2', ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router2',
'neutron:cidrs': '10.10.10.2/24'}, 'neutron:cidrs': '10.10.10.2/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router', 'type': 'router',
'options': { 'options': {
'router-port': 'lrp-bar-name'}, 'router-port': 'lrp-bar-name'},
@ -1866,7 +1873,9 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row( lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={ attrs={
'external_ids': { 'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1'}, ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router', 'type': 'router',
'options': { 'options': {
'router-port': 'lrp-lrp-foo-name'} 'router-port': 'lrp-lrp-foo-name'}