ovs/vsctl: more commands

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Isaku Yamahata
2013-02-08 12:28:07 +09:00
committed by FUJITA Tomonori
parent 966099ce34
commit f8a99a3be2

View File

@@ -18,7 +18,9 @@
import gevent
import itertools
import logging
import operator
import os
import sys
import weakref
import ovs.db.data
@@ -213,6 +215,21 @@ class VSCtlContext(object):
self.bridges[name] = vsctl_bridge
return vsctl_bridge
def del_cached_bridge(self, vsctl_bridge):
assert not vsctl_bridge.ports
assert not vsctl_bridge.children
parent = vsctl_bridge.parent
if parent:
parent.children.remove(vsctl_bridge)
vsctl_bridge.parent = None # break circular reference
ovsrec_bridge = vsctl_bridge.br_cfg
if ovsrec_bridge:
ovsrec_bridge.delete()
self.ovs_delete_bridge(ovsrec_bridge)
del self.bridges[vsctl_bridge.name]
def add_port_to_cache(self, vsctl_bridge_parent, ovsrec_port):
tag = getattr(ovsrec_port, vswitch_idl.OVSREC_PORT_COL_TAG, None)
if (tag is not None and tag >= 0 and tag < 4096):
@@ -428,6 +445,16 @@ class VSCtlContext(object):
vswitch_idl.OVSREC_BRIDGE_COL_PORTS,
ovsrec_port)
def ovs_insert_bridge(self, ovsrec_bridge):
self._column_insert(self.ovs,
vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
ovsrec_bridge)
def ovs_delete_bridge(self, ovsrec_bridge):
self._column_delete(self.ovs,
vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
ovsrec_bridge)
def del_port(self, vsctl_port):
if vsctl_port.bridge().parent:
ovsrec_bridge = vsctl_port.bridge().parent.br_cfg
@@ -439,6 +466,13 @@ class VSCtlContext(object):
self.del_cached_iface(vsctl_iface)
self.del_cached_port(vsctl_port)
def del_bridge(self, vsctl_bridge):
for child in vsctl_bridge.children.copy():
self.del_bridge(child)
for vsctl_port in vsctl_bridge.ports.copy():
self.del_port(vsctl_port)
self.del_cached_bridge(vsctl_bridge)
def add_port(self, br_name, port_name, may_exist, fake_iface,
iface_names, settings=None):
"""
@@ -504,6 +538,77 @@ class VSCtlContext(object):
for ovsrec_iface in ifaces:
self.add_iface_to_cache(vsctl_port, ovsrec_iface)
def add_bridge(self, br_name, parent_name=None, vlan=0, may_exist=False):
self.populate_cache()
if may_exist:
vsctl_bridge = self.find_bridge(br_name, False)
if vsctl_bridge:
if not parent_name:
if vsctl_bridge.parent:
vsctl_fatal('"--may-exist add-vsctl_bridge %s" '
'but %s is a VLAN bridge for VLAN %d' %
(br_name, br_name, vsctl_bridge.vlan))
else:
if not vsctl_bridge.parent:
vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
'but %s is not a VLAN bridge' %
(br_name, parent_name, vlan, br_name))
elif vsctl_bridge.parent.name != parent_name:
vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
'but %s has the wrong parent %s' %
(br_name, parent_name, vlan,
br_name, vsctl_bridge.parent.name))
elif vsctl_bridge.vlan != vlan:
vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
'but %s is a VLAN bridge for the wrong '
'VLAN %d' %
(br_name, parent_name, vlan, br_name,
vsctl_bridge.vlan))
return
self.check_conflicts(br_name,
'cannot create a bridge named %s' % br_name)
txn = self.txn
tables = self.idl.tables
if not parent_name:
ovsrec_iface = txn.insert(
tables[vswitch_idl.OVSREC_TABLE_INTERFACE])
ovsrec_iface.name = br_name
ovsrec_iface.type = 'internal'
ovsrec_port = txn.insert(tables[vswitch_idl.OVSREC_TABLE_PORT])
ovsrec_port.name = br_name
ovsrec_port.interfaces = [ovsrec_iface]
ovsrec_port.fake_bridge = False
ovsrec_bridge = txn.insert(tables[vswitch_idl.OVSREC_TABLE_BRIDGE])
ovsrec_bridge.name = br_name
ovsrec_bridge.ports = [ovsrec_port]
self.ovs_insert_bridge(ovsrec_bridge)
else:
parent = self.find_bridge(parent_name, False)
if parent and parent.parent:
vsctl_fatal('cannot create bridge with fake bridge as parent')
if not parent:
vsctl_fatal('parent bridge %s does not exist' % parent_name)
ovsrec_iface = txn.insert(
tables[vswitch_idl.OVSREC_TABLE_INTERFACE])
ovsrec_iface.name = br_name
ovsrec_iface.type = 'internal'
ovsrec_port = txn.insert(tables[vswitch_idl.OVSREC_TABLE_PORT])
ovsrec_port.name = br_name
ovsrec_port.interfaces = [ovsrec_iface]
ovsrec_port.fake_bridge = True
ovsrec_port.tag = [vlan]
self.bridge_insert_port(parent.br_cfg, ovsrec_port)
self.invalidate_cache()
@staticmethod
def parse_column_key_value(table_schema, setting_string):
"""
@@ -615,6 +720,15 @@ class VSCtlContext(object):
return ovsrec_row
class _CmdShowTable(object):
def __init__(self, table, name_column, columns, recurse):
super(_CmdShowTable, self).__init__()
self.table = table
self.name_column = name_column
self.columns = columns
self.recurse = recurse
class _VSCtlRowID(object):
def __init__(self, table, name_column, uuid_column):
super(_VSCtlRowID, self).__init__()
@@ -826,19 +940,53 @@ class VSCtl(object):
:type commands: list of VSCtlCommand
"""
all_commands = {
# Open vSwitch commands.
'init': (None, self._cmd_init),
'show': (self._pre_cmd_show, self._cmd_show),
# Bridge commands.
'add-br': (self._pre_add_br, self._cmd_add_br),
'del-br': (self._pre_get_info, self._cmd_del_br),
'list-br': (self._pre_get_info, self._cmd_list_br),
# Port. commands
'list-ports': (self._pre_get_info, self._cmd_list_ports),
'add-port': (self._pre_cmd_add_port, self._cmd_add_port),
'del-port': (self._pre_get_info, self._cmd_del_port),
# 'add-bond':
# 'port-to-br':
# Interface commands.
'list-ifaces': (self._pre_get_info, self._cmd_list_ifaces),
# 'iface-to-br':
# Controller commands.
'get-controller': (self._pre_controller, self._cmd_get_controller),
'del-controller': (self._pre_controller, self._cmd_del_controller),
'set-controller': (self._pre_controller, self._cmd_set_controller),
# 'get-fail-mode':
# 'del-fail-mode':
# 'set-fail-mode':
# Manager commands.
# 'get-manager':
# 'del-manager':
# 'set-manager':
# Switch commands.
# 'emer-reset':
# Database commands.
# 'comment':
'get': (self._pre_cmd_get, self._cmd_get),
# 'list':
'find': (self._pre_cmd_find, self._cmd_find),
'set': (self._pre_cmd_set, self._cmd_set),
# 'add':
'clear': (self._pre_cmd_clear, self._cmd_clear),
# 'create':
# 'destroy':
# 'wait-until':
# for quantum_adapter
'list-ifaces-verbose': (self._pre_cmd_list_ifaces_verbose,
@@ -857,6 +1005,112 @@ class VSCtl(object):
with gevent.Timeout(timeout_msec * 1000, exception):
self._run_command(commands)
# commands
def _cmd_init(self, _ctx, _command):
# nothing. Just check connection to ovsdb
pass
_CMD_SHOW_TABLES = [
_CmdShowTable(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH, None,
[vswitch_idl.OVSREC_OPEN_VSWITCH_COL_MANAGER_OPTIONS,
vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
vswitch_idl.OVSREC_OPEN_VSWITCH_COL_OVS_VERSION],
False),
_CmdShowTable(vswitch_idl.OVSREC_TABLE_BRIDGE,
vswitch_idl.OVSREC_BRIDGE_COL_NAME,
[vswitch_idl.OVSREC_BRIDGE_COL_CONTROLLER,
vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE,
vswitch_idl.OVSREC_BRIDGE_COL_PORTS],
False),
_CmdShowTable(vswitch_idl.OVSREC_TABLE_PORT,
vswitch_idl.OVSREC_PORT_COL_NAME,
[vswitch_idl.OVSREC_PORT_COL_TAG,
vswitch_idl.OVSREC_PORT_COL_TRUNKS,
vswitch_idl.OVSREC_PORT_COL_INTERFACES],
False),
_CmdShowTable(vswitch_idl.OVSREC_TABLE_INTERFACE,
vswitch_idl.OVSREC_INTERFACE_COL_NAME,
[vswitch_idl.OVSREC_INTERFACE_COL_TYPE,
vswitch_idl.OVSREC_INTERFACE_COL_OPTIONS],
False),
_CmdShowTable(vswitch_idl.OVSREC_TABLE_CONTROLLER,
vswitch_idl.OVSREC_CONTROLLER_COL_TARGET,
[vswitch_idl.OVSREC_CONTROLLER_COL_IS_CONNECTED],
False),
_CmdShowTable(vswitch_idl.OVSREC_TABLE_MANAGER,
vswitch_idl.OVSREC_MANAGER_COL_TARGET,
[vswitch_idl.OVSREC_MANAGER_COL_IS_CONNECTED],
False),
]
def _pre_cmd_show(self, _ctx, _command):
schema_helper = self.schema_helper
for show in self._CMD_SHOW_TABLES:
schema_helper.register_table(show.table)
if show.name_column:
schema_helper.register_columns(show.table, [show.name_column])
schema_helper.register_columns(show.table, show.columns)
@staticmethod
def _cmd_show_find_table_by_row(row):
for show in VSCtl._CMD_SHOW_TABLES:
if show.table == row._table.name:
return show
return None
@staticmethod
def _cmd_show_find_table_by_name(name):
for show in VSCtl._CMD_SHOW_TABLES:
if show.table == name:
return show
return None
@staticmethod
def _cmd_show_row(ctx, row, level):
_INDENT_SIZE = 4 # # of spaces per indent
show = VSCtl._cmd_show_find_table_by_row(row)
output = ''
output += ' ' * level * _INDENT_SIZE
if show and show.name_column:
output += '%s ' % show.table
datum = getattr(row, show.name_column)
output += datum
else:
output += str(row.uuid)
output += '\n'
if not show or show.recurse:
return
show.recurse = True
for column in show.columns:
datum = row._data[column]
key = datum.type.key
if (key.type == ovs.db.types.UuidType and key.ref_table_name):
ref_show = VSCtl._cmd_show_find_table_by_name(
key.ref_table_name)
if ref_show:
for atom in datum.values:
ref_row = ctx.idl.tables[ref_show.table].rows.get(
atom.value)
if ref_row:
VSCtl._cmd_show_row(ctx, ref_row, level + 1)
continue
if not datum.is_default():
output += ' ' * (level + 1) * _INDENT_SIZE
output += '%s: %s\n' % (column, datum)
show.recurse = False
return output
def _cmd_show(self, ctx, command):
for row in ctx.idl.tables[
self._CMD_SHOW_TABLES[0].table].rows.values():
output = self._cmd_show_row(ctx, row, 0)
command.result = output
def _pre_get_info(self, _ctx, _command):
schema_helper = self.schema_helper
@@ -879,6 +1133,43 @@ class VSCtl(object):
vswitch_idl.OVSREC_TABLE_INTERFACE,
[vswitch_idl.OVSREC_INTERFACE_COL_NAME])
def _cmd_list_br(self, ctx, command):
ctx.populate_cache()
command.result = sorted(ctx.bridges.keys())
def _pre_add_br(self, ctx, command):
self._pre_get_info(ctx, command)
schema_helper = self.schema_helper
schema_helper.register_columns(
vswitch_idl.OVSREC_TABLE_INTERFACE,
[vswitch_idl.OVSREC_INTERFACE_COL_TYPE])
def _cmd_add_br(self, ctx, command):
br_name = command.args[0]
if len(command.args) == 1:
parent_name = None
vlan = 0
elif len(command.args) == 3:
parent_name = command.args[1]
vlan = int(command.args[2])
if vlan < 0 or vlan > 4095:
vsctl_fatal("vlan must be between 0 and 4095 %d" % vlan)
else:
vsctl_fatal('this command takes exactly 1 or 3 argument')
ctx.add_bridge(br_name, parent_name, vlan)
def _del_br(self, ctx, br_name, must_exist=False):
ctx.populate_cache()
br = ctx.find_bridge(br_name, must_exist)
if br:
ctx.del_bridge(br)
def _cmd_del_br(self, ctx, command):
br_name = command.args[0]
self._del_br(ctx, br_name)
def _list_ports(self, ctx, br_name):
ctx.populate_cache()
br = ctx.find_bridge(br_name, True)
@@ -962,6 +1253,25 @@ class VSCtl(object):
br_name = command.args[0] if len(command.args) == 2 else None
self._del_port(ctx, br_name, target, must_exist, with_iface)
def _list_ifaces(self, ctx, br_name):
ctx.populate_cache()
br = ctx.find_bridge(br_name, True)
ctx.verify_ports()
iface_names = set()
for vsctl_port in br.ports:
for vsctl_iface in vsctl_port.ifaces:
iface_name = vsctl_iface.iface_cfg.name
if iface_name != br_name:
iface_names.add(iface_name)
return iface_names
def _cmd_list_ifaces(self, ctx, command):
br_name = command.args[0]
iface_names = self._list_ifaces(ctx, br_name)
command.result = sorted(iface_names)
def _pre_cmd_list_ifaces_verbose(self, ctx, command):
self._pre_get_info(ctx, command)
schema_helper = self.schema_helper
@@ -1028,6 +1338,17 @@ class VSCtl(object):
vswitch_idl.OVSREC_TABLE_CONTROLLER,
[vswitch_idl.OVSREC_CONTROLLER_COL_TARGET])
def _get_controller(self, ctx, br_name):
ctx.populate_cache()
br = ctx.find_bridge(br_name, True)
self._verify_controllers(br.br_cfg)
return set(controller.target for controller in br.br_cfg.controller)
def _cmd_get_controller(self, ctx, command):
br_name = command.args[0]
controller_names = self._get_controller(ctx, br_name)
command.result = sorted(controller_names)
def _delete_controllers(self, ovsrec_controllers):
for controller in ovsrec_controllers:
controller.delete()
@@ -1339,3 +1660,75 @@ class VSCtl(object):
for column_key_value in command.args[2:]]
self._set(ctx, table_name, record_id, column_key_values)
def _pre_clear(self, ctx, table_name, column):
self._pre_get_table(ctx, table_name)
self._pre_get_column(ctx, table_name, column)
self._check_mutable(table_name, column)
def _pre_cmd_clear(self, ctx, command):
table_name = command.args[0]
column = command.args[2]
self._pre_clear(ctx, table_name, column)
def _clear(self, ctx, table_name, record_id, column):
vsctl_table = self._get_table(table_name)
ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
column_schema = ctx.idl.tables[table_name].columns[column]
if column_schema.type.n_min > 0:
vsctl_fatal('"clear" operation cannot be applied to column %s '
'of table %s, which is not allowed to be empty' %
(column, table_name))
# assuming that default datum is empty.
default_datum = ovs.db.data.Datum.default(column_schema.type)
setattr(ovsrec_row, column,
default_datum.to_python(ovs.db.idl._uuid_to_row))
ctx.invalidate_cache()
def _cmd_clear(self, ctx, command):
table_name = command.args[0]
record_id = command.args[1]
column = command.args[2]
self._clear(ctx, table_name, record_id, column)
#
# Create constants from ovs db schema
#
def schema_print(schema_location, prefix):
prefix = prefix.upper()
json = ovs.json.from_file(schema_location)
schema = ovs.db.schema.DbSchema.from_json(json)
print '# Do NOT edit.'
print '# This is automatically generated.'
print '# created based on version %s' % (schema.version or 'unknown')
print ''
print ''
print '%s_DB_NAME = \'%s\'' % (prefix, schema.name)
for table in sorted(schema.tables.values(),
key=operator.attrgetter('name')):
print ''
print '%s_TABLE_%s = \'%s\'' % (prefix,
table.name.upper(), table.name)
for column in sorted(table.columns.values(),
key=operator.attrgetter('name')):
print '%s_%s_COL_%s = \'%s\'' % (prefix, table.name.upper(),
column.name.upper(),
column.name)
def main():
if len(sys.argv) <= 2:
print 'Usage: %s <schema file> <prefix>' % sys.argv[0]
location = sys.argv[1]
prefix = sys.argv[2]
schema_print(location, prefix)
if __name__ == '__main__':
main()