Enable filtering the OVSDB schema tables/columns

Adds the ability to filter the OVSDB scheme to only include specified
tables from the config as well as filter out (exclude) specific table
columns.  If neither of the values are defined in the config, then the
discovered schema is used unchanged.  The is needed to calm down noise with
unused tables/columns to help with scale problems on hosts with a large
number of bridges and interfaces.

Signed-off-by: Alan Quillin <alanquillin@gmail.com>
Acked-By: Jason Kölker <jason@koelker.net>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Alan Quillin 2016-05-03 12:54:28 -04:00 committed by FUJITA Tomonori
parent dbe6743742
commit 7db022bf71
2 changed files with 90 additions and 3 deletions

View File

@ -15,6 +15,7 @@
import collections
import errno
import six
import uuid
from ovs import jsonrpc
@ -132,6 +133,68 @@ def discover_system_id(idl):
return system_id
def _filter_schemas(schemas, schema_tables, exclude_table_columns):
"""Wrapper method for _filter_schema to filter multiple schemas."""
return [_filter_schema(s, schema_tables, exclude_table_columns)
for s in schemas]
def _filter_schema(schema, schema_tables, exclude_table_columns):
"""Filters a schema to only include the specified tables in the
schema_tables parameter. This will also filter out any colums for
included tables that reference tables that are not included
in the schema_tables parameter
:param schema: Schema dict to be filtered
:param schema_tables: List of table names to filter on.
EX: ['Bridge', 'Controller', 'Interface']
NOTE: This list is case sensitive.
:return: Schema dict:
filtered if the schema_table parameter contains table names,
else the original schema dict
"""
tables = {}
for tbl_name, tbl_data in schema['tables'].iteritems():
if not schema_tables or tbl_name in schema_tables:
columns = {}
exclude_columns = exclude_table_columns.get(tbl_name, [])
for col_name, col_data in tbl_data['columns'].iteritems():
if col_name in exclude_columns:
continue
# NOTE(Alan Quillin) Needs to check and remove
# and columns that have references to tables that
# are not to be configured
type_ = col_data.get('type')
if type_:
if type_ and isinstance(type_, dict):
key = type_.get('key')
if key and isinstance(key, dict):
ref_tbl = key.get('refTable')
if ref_tbl and isinstance(ref_tbl,
six.string_types):
if ref_tbl not in schema_tables:
continue
value = type_.get('value')
if value and isinstance(value, dict):
ref_tbl = value.get('refTable')
if ref_tbl and isinstance(ref_tbl,
six.string_types):
if ref_tbl not in schema_tables:
continue
columns[col_name] = col_data
tbl_data['columns'] = columns
tables[tbl_name] = tbl_data
schema['tables'] = tables
return schema
# NOTE(jkoelker) Wrap ovs's Idl to accept an existing session, and
# trigger callbacks on changes
class Idl(idl.Idl):
@ -218,7 +281,8 @@ class RemoteOvsdb(app_manager.RyuApp):
@classmethod
def factory(cls, sock, address, probe_interval=None, min_backoff=None,
max_backoff=None, *args, **kwargs):
max_backoff=None, schema_tables=None,
schema_exclude_columns={}, *args, **kwargs):
ovs_stream = stream.Stream(sock, None, None)
connection = jsonrpc.Connection(ovs_stream)
schemas = discover_schemas(connection)
@ -226,6 +290,10 @@ class RemoteOvsdb(app_manager.RyuApp):
if not schemas:
return
if schema_tables or schema_exclude_columns:
schemas = _filter_schemas(schemas, schema_tables,
schema_exclude_columns)
fsm = reconnect.Reconnect(now())
fsm.set_name('%s:%s' % address)
fsm.enable(now())

View File

@ -36,7 +36,14 @@ opts = (cfg.StrOpt('address', default='0.0.0.0', help='OVSDB address'),
cfg.StrOpt('mngr-privkey', default=None, help='manager private key'),
cfg.StrOpt('mngr-cert', default=None, help='manager certificate'),
cfg.ListOpt('whitelist', default=[],
help='Whitelist of address to allow to connect'))
help='Whitelist of address to allow to connect'),
cfg.ListOpt('schema-tables', default=[],
help='Tables in the OVSDB schema to configure'),
cfg.ListOpt('schema-exclude-columns', default=[],
help='Table columns in the OVSDB schema to filter out. '
'Values should be in the format: <table>.<column>.'
'Ex: Bridge.netflow,Interface.statistics')
)
cfg.CONF.register_opts(opts, 'ovsdb')
@ -119,10 +126,22 @@ class OVSDB(app_manager.RyuApp):
return self.send_event(client_name, ev)
def _start_remote(self, sock, client_address):
schema_tables = cfg.CONF.ovsdb.schema_tables
schema_ex_col = {}
if cfg.CONF.ovsdb.schema_exclude_columns:
for c in cfg.CONF.ovsdb.schema_exclude_columns:
tbl, col = c.split('.')
if tbl in schema_ex_col:
schema_ex_col[tbl].append(col)
else:
schema_ex_col[tbl] = [col]
app = client.RemoteOvsdb.factory(sock, client_address,
probe_interval=self._probe_interval,
min_backoff=self._min_backoff,
max_backoff=self._max_backoff)
max_backoff=self._max_backoff,
schema_tables=schema_tables,
schema_exclude_columns=schema_ex_col)
if app:
self._clients[app.name] = app