Merge "[ovn] Honor enable_default_route_ecmp
attribute"
This commit is contained in:
commit
a98336043f
neutron
common/ovn
plugins/ml2/drivers/ovn/mech_driver/ovsdb
tests
functional/services/ovn_l3
unit
@ -40,6 +40,7 @@ from neutron_lib.api.definitions import flavors
|
||||
from neutron_lib.api.definitions import floating_ip_port_forwarding
|
||||
from neutron_lib.api.definitions import floatingip_pools
|
||||
from neutron_lib.api.definitions import l3
|
||||
from neutron_lib.api.definitions import l3_enable_default_route_ecmp
|
||||
from neutron_lib.api.definitions import l3_ext_gw_mode
|
||||
from neutron_lib.api.definitions import l3_ext_gw_multihoming
|
||||
from neutron_lib.api.definitions import l3_flavors
|
||||
@ -120,6 +121,7 @@ ML2_SUPPORTED_API_EXTENSIONS_OVN_L3 = [
|
||||
flavors.ALIAS,
|
||||
l3_flavors.ALIAS,
|
||||
l3_ext_gw_multihoming.ALIAS,
|
||||
l3_enable_default_route_ecmp.ALIAS,
|
||||
]
|
||||
ML2_SUPPORTED_API_EXTENSIONS = [
|
||||
address_group.ALIAS,
|
||||
|
@ -1257,6 +1257,8 @@ class OVNClient(object):
|
||||
|
||||
def _add_router_ext_gw(self, context, router, networks, txn):
|
||||
lrouter_name = utils.ovn_name(router['id'])
|
||||
router_default_route_ecmp_enabled = router.get(
|
||||
'enable_default_route_ecmp', False)
|
||||
|
||||
# 1. Add the external gateway router port.
|
||||
admin_context = context.elevated()
|
||||
@ -1267,6 +1269,11 @@ class OVNClient(object):
|
||||
added_ports.append(port)
|
||||
|
||||
# 2. Add default route with nexthop as gateway ip
|
||||
if (gw_port['id'] != router.get('gw_port_id') and
|
||||
not router_default_route_ecmp_enabled):
|
||||
# The `enable_default_route_ecmp` option is not enabled for
|
||||
# the router, only adding routes for the first gw_port.
|
||||
continue
|
||||
for gw_info in self._get_gw_info(admin_context, gw_port):
|
||||
if gw_info.gateway_ip is None:
|
||||
continue
|
||||
|
@ -42,7 +42,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
||||
self.cr_lrp_pb_event = events.WaitForCrLrpPortBindingEvent()
|
||||
self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event)
|
||||
|
||||
def _create_router(self, name, gw_info=None, az_hints=None):
|
||||
def _create_router(self, name, gw_info=None, az_hints=None,
|
||||
enable_ecmp=None):
|
||||
router = {'router':
|
||||
{'name': name,
|
||||
'admin_state_up': True,
|
||||
@ -51,6 +52,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
||||
router['router']['availability_zone_hints'] = az_hints
|
||||
if gw_info:
|
||||
router['router']['external_gateway_info'] = gw_info
|
||||
if enable_ecmp:
|
||||
router['router']['enable_default_route_ecmp'] = enable_ecmp
|
||||
return self.l3_plugin.create_router(self.context, router)
|
||||
|
||||
def _add_external_gateways(self, router_id, external_gateways):
|
||||
@ -531,10 +534,36 @@ class TestRouter(base.TestOVNFunctionalBase):
|
||||
len(lr.ports),
|
||||
len(gws['router']['external_gateways']))
|
||||
|
||||
self.assertEqual(
|
||||
len(lr.static_routes),
|
||||
1)
|
||||
|
||||
self.l3_plugin.delete_router(self.context, id=router['id'])
|
||||
self.assertRaises(idlutils.RowNotFound, self.nb_api.lookup,
|
||||
'Logical_Router', ovn_utils.ovn_name(router['id']))
|
||||
|
||||
def test_create_router_multiple_gw_ports_ecmp(self):
|
||||
ext5 = self._create_ext_network(
|
||||
'ext5', 'flat', 'physnet5', None, "10.0.50.1", "10.0.50.0/24")
|
||||
router = self._create_router('router5', enable_ecmp=True)
|
||||
gws = self._add_external_gateways(
|
||||
router['id'],
|
||||
[
|
||||
{'network_id': ext5['network']['id']},
|
||||
{'network_id': ext5['network']['id']},
|
||||
]
|
||||
)
|
||||
lr = self.nb_api.lookup('Logical_Router',
|
||||
ovn_utils.ovn_name(router['id']))
|
||||
# Check that the expected number of ports are created
|
||||
self.assertEqual(
|
||||
len(lr.ports),
|
||||
len(gws['router']['external_gateways']))
|
||||
# Check that the expected number of static routes are created
|
||||
self.assertEqual(
|
||||
len(lr.static_routes),
|
||||
len(gws['router']['external_gateways']))
|
||||
|
||||
def test_gateway_chassis_rebalance(self):
|
||||
def _get_result_dict():
|
||||
sched_info = {}
|
||||
|
@ -71,6 +71,7 @@ class TestOVNClient(TestOVNClientBase):
|
||||
self.ovn_client._get_router_gw_ports = mock.MagicMock()
|
||||
gw_port = fakes.FakePort().create_one_port(
|
||||
attrs={
|
||||
'id': router['gw_port_id'],
|
||||
'fixed_ips': [{
|
||||
'subnet_id': subnet.get('id'),
|
||||
'ip_address': '10.42.0.42'}]
|
||||
@ -88,6 +89,66 @@ class TestOVNClient(TestOVNClientBase):
|
||||
'neutron:is_ext_gw': 'true',
|
||||
'neutron:subnet_id': subnet['id']})
|
||||
|
||||
def test__add_router_ext_gw_default_route_ecmp(self):
|
||||
plugin = mock.MagicMock()
|
||||
self.get_plugin.return_value = plugin
|
||||
subnet1 = {
|
||||
'id': 'fake-subnet-id-1',
|
||||
'gateway_ip': '10.42.0.1',
|
||||
'ip_version': const.IP_VERSION_4,
|
||||
}
|
||||
subnet2 = {
|
||||
'id': 'fake-subnet-id-2',
|
||||
'gateway_ip': '10.42.42.1',
|
||||
'ip_version': const.IP_VERSION_4,
|
||||
}
|
||||
plugin.get_subnet.side_effect = [subnet1, subnet2, subnet1, subnet2]
|
||||
plugin.get_subnets_by_network.return_value = [subnet1, subnet2]
|
||||
router = {
|
||||
'id': 'fake-router-id',
|
||||
'gw_port_id': 'fake-port-id',
|
||||
'enable_default_route_ecmp': True,
|
||||
}
|
||||
networks = mock.MagicMock()
|
||||
txn = mock.MagicMock()
|
||||
self.ovn_client._get_router_gw_ports = mock.MagicMock()
|
||||
gw_port1 = fakes.FakePort().create_one_port(
|
||||
attrs={
|
||||
'id': router['gw_port_id'],
|
||||
'fixed_ips': [{
|
||||
'subnet_id': subnet1.get('id'),
|
||||
'ip_address': '10.42.0.42'}]
|
||||
})
|
||||
gw_port2 = fakes.FakePort().create_one_port(
|
||||
attrs={
|
||||
'id': 'gw-port-id-2',
|
||||
'fixed_ips': [{
|
||||
'subnet_id': subnet2.get('id'),
|
||||
'ip_address': '10.42.42.42'}]
|
||||
})
|
||||
self.ovn_client._get_router_gw_ports.return_value = [
|
||||
gw_port1, gw_port2]
|
||||
self.assertEqual(
|
||||
[self.get_plugin().get_port(), self.get_plugin().get_port()],
|
||||
self.ovn_client._add_router_ext_gw(mock.Mock(), router,
|
||||
networks, txn))
|
||||
self.nb_idl.add_static_route.assert_has_calls([
|
||||
mock.call('neutron-' + router['id'],
|
||||
ip_prefix='0.0.0.0/0',
|
||||
nexthop=subnet1['gateway_ip'],
|
||||
external_ids={
|
||||
'neutron:is_ext_gw': 'true',
|
||||
'neutron:subnet_id': subnet1['id']},
|
||||
),
|
||||
mock.call('neutron-' + router['id'],
|
||||
ip_prefix='0.0.0.0/0',
|
||||
nexthop=subnet2['gateway_ip'],
|
||||
external_ids={
|
||||
'neutron:is_ext_gw': 'true',
|
||||
'neutron:subnet_id': subnet2['id']},
|
||||
),
|
||||
])
|
||||
|
||||
def test__add_router_ext_gw_no_default_route(self):
|
||||
plugin = mock.MagicMock()
|
||||
self.get_plugin.return_value = plugin
|
||||
@ -112,6 +173,7 @@ class TestOVNClient(TestOVNClientBase):
|
||||
self.ovn_client._get_router_gw_ports = mock.MagicMock()
|
||||
gw_port = fakes.FakePort().create_one_port(
|
||||
attrs={
|
||||
'id': router['gw_port_id'],
|
||||
'fixed_ips': [{
|
||||
'subnet_id': subnet.get('id'),
|
||||
'ip_address': '10.42.0.42'}]
|
||||
|
@ -835,7 +835,13 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
grps.return_value = self.fake_router_ports
|
||||
fake_old_ext_gw_port = self.fake_ext_gw_port.copy()
|
||||
fake_old_ext_gw_port['id'] = 'old-gw-port-id'
|
||||
self._get_router_gw_ports.return_value = [fake_old_ext_gw_port]
|
||||
self._get_router_gw_ports.return_value = None
|
||||
self._get_router_gw_ports.side_effect = [
|
||||
[fake_old_ext_gw_port],
|
||||
[fake_old_ext_gw_port],
|
||||
[self.fake_ext_gw_port],
|
||||
[self.fake_ext_gw_port],
|
||||
]
|
||||
|
||||
payload = self._create_payload_for_router_update(
|
||||
self.get_router.return_value, self.fake_router_with_ext_gw)
|
||||
|
Loading…
x
Reference in New Issue
Block a user