Merge "Add extra router attributes for ECMP and BFD"

This commit is contained in:
Zuul 2023-08-08 23:40:38 +00:00 committed by Gerrit Code Review
commit 176b144460
13 changed files with 276 additions and 7 deletions

View File

@ -0,0 +1,36 @@
# Copyright (c) 2023 Canonical Ltd.
#
# 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.
from oslo_config import cfg
from neutron._i18n import _
L3_EXTRA_GWS_OPTS = [
cfg.BoolOpt('enable_default_route_ecmp',
default=False,
help=_("Define the default value for "
"enable_default_route_ecmp if not specified on the "
"router.")),
cfg.BoolOpt('enable_default_route_bfd',
default=False,
help=_("Define the default value for "
"enable_default_route_bfd if not specified on the "
"router.")),
]
def register_db_l3_extragws_opts(conf=cfg.CONF):
conf.register_opts(L3_EXTRA_GWS_OPTS)

View File

@ -127,6 +127,22 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
policy.DocumentedRuleDefault(
name='create_router:enable_default_route_bfd',
check_str=base.ADMIN,
scope_types=['project'],
description=('Specify ``enable_default_route_bfd`` attribute when'
' creating a router'),
operations=ACTION_POST,
),
policy.DocumentedRuleDefault(
name='create_router:enable_default_route_ecmp',
check_str=base.ADMIN,
scope_types=['project'],
description=('Specify ``enable_default_route_ecmp`` attribute when'
' creating a router'),
operations=ACTION_POST,
),
policy.DocumentedRuleDefault(
name='get_router',
@ -252,6 +268,22 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
policy.DocumentedRuleDefault(
name='update_router:enable_default_route_bfd',
check_str=base.ADMIN,
scope_types=['project'],
description=('Specify ``enable_default_route_bfd`` attribute when '
'updating a router'),
operations=ACTION_POST,
),
policy.DocumentedRuleDefault(
name='update_router:enable_default_route_ecmp',
check_str=base.ADMIN,
scope_types=['project'],
description=('Specify ``enable_default_route_ecmp`` attribute when '
'updating a router'),
operations=ACTION_POST,
),
policy.DocumentedRuleDefault(
name='delete_router',

View File

@ -18,9 +18,13 @@ from neutron_lib.db import resource_extend
from oslo_config import cfg
from neutron._i18n import _
from neutron.conf.db import l3_extra_gws_db
from neutron.db.models import l3_attrs
l3_extra_gws_db.register_db_l3_extragws_opts()
def get_attr_info():
"""Returns api visible attr names and their default values."""
return {'distributed': {'default': cfg.CONF.router_distributed},
@ -29,7 +33,11 @@ def get_attr_info():
'availability_zone_hints': {
'default': '[]',
'transform_to_db': az_validator.convert_az_list_to_string,
'transform_from_db': az_validator.convert_az_string_to_list}
'transform_from_db': az_validator.convert_az_string_to_list},
'enable_default_route_ecmp': {
'default': cfg.CONF.enable_default_route_ecmp},
'enable_default_route_bfd': {
'default': cfg.CONF.enable_default_route_bfd},
}

View File

@ -22,6 +22,8 @@ from neutron.db import l3_gwmode_db
from neutron.objects import ports as port_obj
from neutron.objects import router as l3_obj
from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import l3_enable_default_route_bfd
from neutron_lib.api.definitions import l3_enable_default_route_ecmp
from neutron_lib.api.definitions import l3_ext_gw_multihoming
from neutron_lib.api import extensions
from neutron_lib.callbacks import events
@ -75,6 +77,16 @@ class ExtraGatewaysDbOnlyMixin(l3_gwmode_db.L3_NAT_dbonly_mixin):
trigger, payload):
self._remove_all_gateways(payload.context, payload.resource_id)
@registry.receives(resources.ROUTER, [events.PRECOMMIT_CREATE])
def _process_bfd_ecmp_request(self, resource, event, trigger, payload):
router = payload.latest_state
router_db = payload.metadata['router_db']
for attr in (l3_enable_default_route_ecmp.ENABLE_DEFAULT_ROUTE_ECMP,
l3_enable_default_route_bfd.ENABLE_DEFAULT_ROUTE_BFD):
value = router.get(attr)
if value is not None:
self.set_extra_attr_value(router_db, attr, value)
def _add_external_gateways(
self, context, router_id, gw_info_list, payload):
"""Add external gateways to a router."""

View File

@ -0,0 +1,39 @@
# Copyright 2023 OpenStack Foundation
#
# 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.
#
from alembic import op
import sqlalchemy as sa
from sqlalchemy import sql
"""Add ECMP and BFD router-level policy attributes
Revision ID: 89c58a70ceba
Revises: c33da356b165
Create Date: 2023-02-22 21:08:33.593101
"""
# revision identifiers, used by Alembic.
revision = '89c58a70ceba'
down_revision = 'c33da356b165'
def upgrade():
op.add_column('router_extra_attributes',
sa.Column('enable_default_route_ecmp', sa.Boolean(),
server_default=sql.false(), nullable=False))
op.add_column('router_extra_attributes',
sa.Column('enable_default_route_bfd', sa.Boolean(),
server_default=sql.false(), nullable=False))

View File

@ -1 +1 @@
c33da356b165
89c58a70ceba

View File

@ -40,6 +40,12 @@ class RouterExtraAttributes(model_base.BASEV2):
ha_vr_id = sa.Column(sa.Integer())
# Availability Zone support
availability_zone_hints = sa.Column(sa.String(255))
enable_default_route_ecmp = sa.Column(sa.Boolean, default=False,
server_default=sa.sql.false(),
nullable=False)
enable_default_route_bfd = sa.Column(sa.Boolean, default=False,
server_default=sa.sql.false(),
nullable=False)
router = orm.relationship(
'Router', load_on_pending=True,

View File

@ -71,7 +71,8 @@ class RouterRoute(base.NeutronDbObject):
@base.NeutronObjectRegistry.register
class RouterExtraAttributes(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Added ECMP and BFD attributes
VERSION = '1.1'
db_model = l3_attrs.RouterExtraAttributes
@ -81,7 +82,10 @@ class RouterExtraAttributes(base.NeutronDbObject):
'service_router': obj_fields.BooleanField(default=False),
'ha': obj_fields.BooleanField(default=False),
'ha_vr_id': obj_fields.IntegerField(nullable=True),
'availability_zone_hints': obj_fields.ListOfStringsField(nullable=True)
'availability_zone_hints': obj_fields.ListOfStringsField(
nullable=True),
'enable_default_route_bfd': obj_fields.BooleanField(default=False),
'enable_default_route_ecmp': obj_fields.BooleanField(default=False),
}
primary_keys = ['router_id']
@ -130,6 +134,12 @@ class RouterExtraAttributes(base.NeutronDbObject):
return list(query)
def obj_make_compatible(self, primitive, target_version):
_target_version = versionutils.convert_version_to_tuple(target_version)
if _target_version < (1, 1):
primitive.pop('enable_default_route_bfd', None)
primitive.pop('enable_default_route_ecmp', None)
@base.NeutronObjectRegistry.register
class RouterPort(base.NeutronDbObject):

View File

@ -35,6 +35,7 @@ import neutron.conf.db.dvr_mac_db
import neutron.conf.db.extraroute_db
import neutron.conf.db.l3_agentschedulers_db
import neutron.conf.db.l3_dvr_db
import neutron.conf.db.l3_extra_gws_db
import neutron.conf.db.l3_gwmode_db
import neutron.conf.db.l3_hamode_db
import neutron.conf.experimental
@ -168,7 +169,8 @@ def list_db_opts():
neutron.conf.db.dvr_mac_db.DVR_MAC_ADDRESS_OPTS,
neutron.conf.db.l3_dvr_db.ROUTER_DISTRIBUTED_OPTS,
neutron.conf.db.l3_agentschedulers_db.L3_AGENTS_SCHEDULER_OPTS,
neutron.conf.db.l3_hamode_db.L3_HA_OPTS)
neutron.conf.db.l3_hamode_db.L3_HA_OPTS,
neutron.conf.db.l3_extra_gws_db.L3_EXTRA_GWS_OPTS)
),
('database',
neutron.db.migration.cli.get_engine_config())

View File

@ -114,6 +114,30 @@ class SystemAdminTests(RouterAPITestCase):
'create_router:external_gateway_info:external_fixed_ips',
self.alt_target)
def test_create_router_enable_default_route_bfd(self):
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'create_router:enable_default_route_bfd',
self.target)
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'create_router:enable_default_route_bfd',
self.alt_target)
def test_create_router_enable_default_route_ecmp(self):
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'create_router:enable_default_route_ecmp',
self.target)
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'create_router:enable_default_route_ecmp',
self.alt_target)
def test_get_router(self):
self.assertRaises(
base_policy.InvalidScope,
@ -224,6 +248,30 @@ class SystemAdminTests(RouterAPITestCase):
'update_router:external_gateway_info:external_fixed_ips',
self.alt_target)
def test_update_router_enable_default_route_bfd(self):
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'update_router:enable_default_route_bfd',
self.target)
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'update_router:enable_default_route_bfd',
self.alt_target)
def test_update_router_enable_default_route_ecmp(self):
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'update_router:enable_default_route_ecmp',
self.target)
self.assertRaises(
base_policy.InvalidScope,
policy.enforce,
self.context, 'update_router:enable_default_route_ecmp',
self.alt_target)
def test_delete_router(self):
self.assertRaises(
base_policy.InvalidScope,
@ -337,6 +385,30 @@ class AdminTests(RouterAPITestCase):
'create_router:external_gateway_info:external_fixed_ips',
self.alt_target))
def test_update_router_enable_default_route_bfd(self):
self.assertTrue(
policy.enforce(
self.context,
'update_router:enable_default_route_bfd',
self.target))
self.assertTrue(
policy.enforce(
self.context,
'update_router:enable_default_route_bfd',
self.alt_target))
def test_update_router_enable_default_route_ecmp(self):
self.assertTrue(
policy.enforce(
self.context,
'update_router:enable_default_route_ecmp',
self.target))
self.assertTrue(
policy.enforce(
self.context,
'update_router:enable_default_route_ecmp',
self.alt_target))
def test_get_router(self):
self.assertTrue(
policy.enforce(self.context, 'get_router', self.target))
@ -524,6 +596,34 @@ class ProjectMemberTests(AdminTests):
'create_router:external_gateway_info:external_fixed_ips',
self.alt_target)
def test_update_router_enable_default_route_bfd(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context,
'update_router:enable_default_route_bfd',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context,
'update_router:enable_default_route_bfd',
self.alt_target)
def test_update_router_enable_default_route_ecmp(self):
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context,
'update_router:enable_default_route_ecmp',
self.target)
self.assertRaises(
base_policy.PolicyNotAuthorized,
policy.enforce,
self.context,
'update_router:enable_default_route_ecmp',
self.alt_target)
def test_get_router(self):
self.assertTrue(
policy.enforce(self.context, 'get_router', self.target))

View File

@ -657,9 +657,17 @@ class ExtraAttributesMixinTestCase(testlib_api.SqlTestCase):
self.mixin.set_extra_attr_value(self.router,
'availability_zone_hints',
['x', 'y', 'z'])
self.mixin.set_extra_attr_value(self.router,
'enable_default_route_ecmp',
True)
self.mixin.set_extra_attr_value(self.router,
'enable_default_route_bfd',
True)
expected = self._get_default_api_values()
expected.update({'ha_vr_id': 99,
'availability_zone_hints': ['x', 'y', 'z']})
'availability_zone_hints': ['x', 'y', 'z'],
'enable_default_route_ecmp': True,
'enable_default_route_bfd': True})
rdict = {}
self.mixin._extend_extra_router_dict(rdict, self.router)
self.assertEqual(expected, rdict)
@ -667,7 +675,15 @@ class ExtraAttributesMixinTestCase(testlib_api.SqlTestCase):
self.mixin.set_extra_attr_value(self.router,
'availability_zone_hints',
['z', 'y', 'z'])
self.mixin.set_extra_attr_value(self.router,
'enable_default_route_ecmp',
False)
self.mixin.set_extra_attr_value(self.router,
'enable_default_route_bfd',
False)
expected['availability_zone_hints'] = ['z', 'y', 'z']
expected['enable_default_route_ecmp'] = False
expected['enable_default_route_bfd'] = False
self.mixin._extend_extra_router_dict(rdict, self.router)
self.assertEqual(expected, rdict)

View File

@ -106,7 +106,7 @@ object_data = {
'ResourceDelta': '1.0-a980b37e0a52618b5af8db29af18be76',
'Route': '1.0-a9883a63b416126f9e345523ec09483b',
'Router': '1.1-614fa16cc99c60e4fc19ac1b31a52291',
'RouterExtraAttributes': '1.0-ef8d61ae2864f0ec9af0ab7939cab318',
'RouterExtraAttributes': '1.1-19c45c32098d2aae8e1a22d18944a954',
'RouterL3AgentBinding': '1.0-c5ba6c95e3a4c1236a55f490cd67da82',
'RouterNDPProxyState': '1.0-4042e475bf173d1d8d17adb962eae1b2',
'RouterPort': '1.0-c8c8f499bcdd59186fcd83f323106908',

View File

@ -0,0 +1,8 @@
---
features:
- |
Add ``enable_default_route_bfd`` and ``enable_default_route_ecmp``
configuration options which control default behavior for enabling BFD and
ECMP on default routes for newly created routers. Both configuration
options have a default value of 'False' and are only supported with the
OVN driver.