1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2012 Isaku Yamahata <yamahata at private email ne jp>
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 ``ovs-vsctl`` command like library to speak OVSDB protocol
21 from __future__ import print_function
38 from ovs import jsonrpc
39 from ovs import ovsuuid
40 from ovs import stream
41 from ovs.db import idl
43 from ryu.lib import hub
44 from ryu.lib import ip
45 from ryu.lib.ovs import vswitch_idl
46 from ryu.lib.stringify import StringifyMixin
49 LOG = logging.getLogger(__name__) # use ovs.vlog?
52 def valid_ovsdb_addr(addr):
54 Returns True if the given addr is valid OVSDB server address, otherwise
57 The valid formats are:
63 If ip is IPv6 address, wrap ip with brackets (e.g., ssl:[::1]:6640).
65 :param addr: str value of OVSDB server address.
66 :return: True if valid, otherwise False.
68 # Assumes Unix socket format: "unix:file"
69 m = re.match(r'unix:(\S+)', addr)
72 return os.path.isfile(file)
73 # Assumes TCP/SSL socket format: "tcp:ip:port" or "ssl:ip:port"
74 m = re.match(r'(tcp|ssl):(\S+):(\d+)', addr)
79 address = address.strip('[').strip(']')
80 return ip.valid_ipv6(address) and port.isdigit()
82 return ip.valid_ipv4(address) and port.isdigit()
83 # Assumes invalid format or unsupported type
88 def ovsrec_row_changes_to_string(ovsrec_row):
89 if not ovsrec_row._changes:
90 return ovsrec_row._changes
92 return dict((key, value.to_string())
93 for key, value in ovsrec_row._changes.items())
97 def ovsrec_row_to_string(ovsrec_row):
99 output += 'uuid: %s ' % ovsrec_row.uuid
101 output += '_data: %s ' % dict((key, value.to_string()) for key, value
102 in ovsrec_row._data.items())
104 output += '_data: %s ' % ovsrec_row._data
105 output += '_changes: %s' % ovsrec_row_changes_to_string(ovsrec_row)
109 def atom_from_string(base, value_string, symtab=None):
112 if type_ == ovs.db.types.IntegerType:
113 atom = ovs.db.data.Atom(type_, int(value_string))
114 elif type_ == ovs.db.types.RealType:
116 atom = ovs.db.data.Atom(
117 type_, ovs.db.parser.float_to_int(float(value_string)))
118 elif type_ == ovs.db.types.BooleanType:
119 if value_string in ("true", "yes", "on", "1"):
120 atom = ovs.db.data.Atom(type_, True)
121 elif value_string == ("false", "no", "off", "0"):
122 atom = ovs.db.data.Atom(type_, False)
123 elif type_ == ovs.db.types.StringType:
124 # TODO:XXXX escape: if value_string[0] == '"':
125 atom = ovs.db.data.Atom(type_, value_string)
126 elif type_ == ovs.db.types.UuidType:
127 if value_string[0] == "@":
128 assert symtab is not None
129 uuid_ = symtab[value_string]
130 atom = ovs.db.data.Atom(type_, uuid_)
132 atom = ovs.db.data.Atom(type_,
133 ovs.ovsuuid.from_string(value_string))
135 raise ValueError("expected %s" % type_.to_string(), value_string)
136 atom.check_constraints(base)
140 def datum_from_string(type_, value_string, symtab=None):
141 value_string = value_string.strip()
143 if value_string.startswith('{'):
145 LOG.debug('value_string %s', value_string)
146 raise NotImplementedError()
147 d = dict(v.split('=', 1) for v in value_string.split(','))
148 d = dict((atom_from_string(type_.key, key, symtab),
149 atom_from_string(type_.value, value, symtab))
150 for key, value in d.items())
152 if value_string.startswith('['):
154 LOG.debug('value_string %s', value_string)
155 raise NotImplementedError()
156 values = value_string.split(',')
157 d = dict((atom_from_string(type_.key, value, symtab), None)
160 atom = atom_from_string(type_.key, value_string, symtab)
163 datum = ovs.db.data.Datum(type_, d)
164 return datum.to_json()
167 def ifind(pred, seq):
169 return [i for i in seq if pred(i)][0]
178 def vsctl_fatal(msg):
180 raise Exception(msg) # not call ovs.utils.ovs_fatal for reusability
183 class VSCtlBridge(object):
185 def __init__(self, ovsrec_bridge, name, parent, vlan):
186 super(VSCtlBridge, self).__init__()
187 self.br_cfg = ovsrec_bridge
192 self.children = set() # WeakSet is needed?
194 def find_vlan_bridge(self, vlan):
195 return ifind(lambda child: child.vlan == vlan, self.children)
198 class VSCtlPort(object):
200 def __init__(self, vsctl_bridge_parent, ovsrec_port):
201 super(VSCtlPort, self).__init__()
202 self.bridge = weakref.ref(vsctl_bridge_parent) # backpointer
203 self.port_cfg = ovsrec_port
209 class VSCtlIface(object):
211 def __init__(self, vsctl_port_parent, ovsrec_iface):
212 super(VSCtlIface, self).__init__()
213 self.port = weakref.ref(vsctl_port_parent) # backpointer
214 self.iface_cfg = ovsrec_iface
217 class VSCtlQoS(object):
219 def __init__(self, vsctl_port_parent, ovsrec_qos):
220 super(VSCtlQoS, self).__init__()
221 self.port = weakref.ref(vsctl_port_parent)
222 self.qos_cfg = ovsrec_qos
226 class VSCtlQueue(object):
228 def __init__(self, vsctl_qos_parent, ovsrec_queue):
229 super(VSCtlQueue, self).__init__()
230 self.qos = weakref.ref(vsctl_qos_parent)
231 self.queue_cfg = ovsrec_queue
234 class VSCtlContext(object):
236 def _invalidate_cache(self):
237 self.cache_valid = False
242 def __init__(self, idl_, txn, ovsrec_open_vswitch):
243 super(VSCtlContext, self).__init__()
249 self.ovs = ovsrec_open_vswitch
250 self.symtab = None # TODO:XXX
251 self.verified_ports = False
253 # A cache of the contents of the database.
254 self.cache_valid = False
255 self.bridges = {} # bridge name -> VSCtlBridge
256 self.ports = {} # port name -> VSCtlPort
257 self.ifaces = {} # iface name -> VSCtlIface
259 self.try_again = False # used by wait-until command
262 self._invalidate_cache()
264 def verify_bridges(self):
265 self.ovs.verify(vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES)
267 def verify_ports(self):
268 if self.verified_ports:
271 self.verify_bridges()
272 for ovsrec_bridge in self.idl.tables[
273 vswitch_idl.OVSREC_TABLE_BRIDGE].rows.values():
274 ovsrec_bridge.verify(vswitch_idl.OVSREC_BRIDGE_COL_PORTS)
275 for ovsrec_port in self.idl.tables[
276 vswitch_idl.OVSREC_TABLE_PORT].rows.values():
277 ovsrec_port.verify(vswitch_idl.OVSREC_PORT_COL_INTERFACES)
278 self.verified_ports = True
280 def add_bridge_to_cache(self, ovsrec_bridge, name, parent, vlan):
281 vsctl_bridge = VSCtlBridge(ovsrec_bridge, name, parent, vlan)
283 parent.children.add(vsctl_bridge)
284 self.bridges[name] = vsctl_bridge
287 def del_cached_bridge(self, vsctl_bridge):
288 assert not vsctl_bridge.ports
289 assert not vsctl_bridge.children
291 parent = vsctl_bridge.parent
293 parent.children.remove(vsctl_bridge)
294 vsctl_bridge.parent = None # break circular reference
295 ovsrec_bridge = vsctl_bridge.br_cfg
297 ovsrec_bridge.delete()
298 self.ovs_delete_bridge(ovsrec_bridge)
300 del self.bridges[vsctl_bridge.name]
302 def del_cached_qos(self, vsctl_qos):
303 vsctl_qos.port().qos = None
304 vsctl_qos.port = None
305 vsctl_qos.queues = None
307 def add_port_to_cache(self, vsctl_bridge_parent, ovsrec_port):
308 tag = getattr(ovsrec_port, vswitch_idl.OVSREC_PORT_COL_TAG, None)
309 if isinstance(tag, list):
314 if tag is not None and 0 <= tag < 4096:
315 vlan_bridge = vsctl_bridge_parent.find_vlan_bridge(tag)
317 vsctl_bridge_parent = vlan_bridge
319 vsctl_port = VSCtlPort(vsctl_bridge_parent, ovsrec_port)
320 vsctl_bridge_parent.ports.add(vsctl_port)
321 self.ports[ovsrec_port.name] = vsctl_port
324 def del_cached_port(self, vsctl_port):
325 assert not vsctl_port.ifaces
326 vsctl_port.bridge().ports.remove(vsctl_port)
327 vsctl_port.bridge = None
328 port = self.ports.pop(vsctl_port.port_cfg.name)
329 assert port == vsctl_port
330 vsctl_port.port_cfg.delete()
332 def add_iface_to_cache(self, vsctl_port_parent, ovsrec_iface):
333 vsctl_iface = VSCtlIface(vsctl_port_parent, ovsrec_iface)
334 vsctl_port_parent.ifaces.add(vsctl_iface)
335 self.ifaces[ovsrec_iface.name] = vsctl_iface
337 def add_qos_to_cache(self, vsctl_port_parent, ovsrec_qos):
338 vsctl_qos = VSCtlQoS(vsctl_port_parent, ovsrec_qos)
339 vsctl_port_parent.qos = vsctl_qos
342 def add_queue_to_cache(self, vsctl_qos_parent, ovsrec_queue):
343 vsctl_queue = VSCtlQueue(vsctl_qos_parent, ovsrec_queue)
344 vsctl_qos_parent.queues.add(vsctl_queue)
346 def del_cached_iface(self, vsctl_iface):
347 vsctl_iface.port().ifaces.remove(vsctl_iface)
348 vsctl_iface.port = None
349 del self.ifaces[vsctl_iface.iface_cfg.name]
350 vsctl_iface.iface_cfg.delete()
352 def invalidate_cache(self):
353 if not self.cache_valid:
355 self._invalidate_cache()
357 def populate_cache(self):
358 self._populate_cache(self.idl.tables[vswitch_idl.OVSREC_TABLE_BRIDGE])
361 def port_is_fake_bridge(ovsrec_port):
362 tag = ovsrec_port.tag
363 if isinstance(tag, list):
368 return ovsrec_port.fake_bridge and 0 <= tag <= 4095
370 def _populate_cache(self, ovsrec_bridges):
373 self.cache_valid = True
377 for ovsrec_bridge in ovsrec_bridges.rows.values():
378 name = ovsrec_bridge.name
380 LOG.warning('%s: database contains duplicate bridge name',
383 vsctl_bridge = self.add_bridge_to_cache(ovsrec_bridge, name,
387 for ovsrec_port in ovsrec_bridge.ports:
388 port_name = ovsrec_port.name
389 if port_name in ports:
390 # Duplicate ovsrec_port name.
391 # (We will warn about that later.)
394 if (self.port_is_fake_bridge(ovsrec_port) and
395 port_name not in bridges):
396 bridges.add(port_name)
397 self.add_bridge_to_cache(None, port_name, vsctl_bridge,
401 for ovsrec_bridge in ovsrec_bridges.rows.values():
402 name = ovsrec_bridge.name
406 vsctl_bridge = self.bridges[name]
407 for ovsrec_port in ovsrec_bridge.ports:
408 port_name = ovsrec_port.name
409 vsctl_port = self.ports.get(port_name)
411 if ovsrec_port == vsctl_port.port_cfg:
412 LOG.warning('%s: vsctl_port is in multiple bridges '
414 port_name, vsctl_bridge.name,
417 LOG.error('%s: database contains duplicate '
422 if (self.port_is_fake_bridge(ovsrec_port) and
423 port_name in bridges):
426 # LOG.debug('ovsrec_port %s %s %s',
427 # ovsrec_port, ovsrec_port._data, ovsrec_port.tag)
428 vsctl_port = self.add_port_to_cache(vsctl_bridge, ovsrec_port)
429 # LOG.debug('vsctl_port %s', vsctl_port)
430 for ovsrec_iface in ovsrec_port.interfaces:
431 iface = self.ifaces.get(ovsrec_iface.name)
433 if ovsrec_iface == iface.iface_cfg:
435 '%s: interface is in multiple ports '
438 iface.port().port_cfg.name,
439 vsctl_port.port_cfg.name)
442 '%s: database contains duplicate interface '
446 self.add_iface_to_cache(vsctl_port, ovsrec_iface)
447 ovsrec_qos = ovsrec_port.qos
448 vsctl_qos = self.add_qos_to_cache(vsctl_port, ovsrec_qos)
450 for ovsrec_queue in ovsrec_qos[0].queues:
451 self.add_queue_to_cache(vsctl_qos, ovsrec_queue)
453 def check_conflicts(self, name, msg):
455 if name in self.bridges:
456 vsctl_fatal('%s because a bridge named %s already exists' %
458 if name in self.ports:
459 vsctl_fatal('%s because a port named %s already exists on '
461 (msg, name, self.ports[name].bridge().name))
462 if name in self.ifaces:
463 vsctl_fatal('%s because an interface named %s already '
464 'exists on bridge %s' %
465 (msg, name, self.ifaces[name].port().bridge().name))
467 def find_bridge(self, name, must_exist):
468 assert self.cache_valid
469 vsctl_bridge = self.bridges.get(name)
470 if must_exist and not vsctl_bridge:
471 vsctl_fatal('no bridge named %s' % name)
472 self.verify_bridges()
475 def find_real_bridge(self, name, must_exist):
476 vsctl_bridge = self.find_bridge(name, must_exist)
477 if vsctl_bridge and vsctl_bridge.parent:
478 vsctl_fatal('%s is a fake bridge' % name)
481 def find_bridge_by_id(self, datapath_id, must_exist):
482 assert self.cache_valid
483 for vsctl_bridge in self.bridges.values():
484 if vsctl_bridge.br_cfg.datapath_id[0].strip('"') == datapath_id:
485 self.verify_bridges()
489 vsctl_fatal('no bridge id %s' % datapath_id)
492 def find_port(self, name, must_exist):
493 assert self.cache_valid
494 vsctl_port = self.ports.get(name)
495 if vsctl_port and name == vsctl_port.bridge().name:
497 if must_exist and not vsctl_port:
498 vsctl_fatal('no vsctl_port named %s' % name)
501 def find_iface(self, name, must_exist):
502 assert self.cache_valid
503 vsctl_iface = self.ifaces.get(name)
504 if vsctl_iface and name == vsctl_iface.port().bridge().name:
506 if must_exist and not vsctl_iface:
507 vsctl_fatal('no interface named %s' % name)
511 def set_qos(self, vsctl_port, type, max_rate):
512 qos = vsctl_port.qos.qos_cfg
514 ovsrec_qos = self.txn.insert(
515 self.txn.idl.tables[vswitch_idl.OVSREC_TABLE_QOS])
516 vsctl_port.port_cfg.qos = [ovsrec_qos]
519 ovsrec_qos.type = type
520 if max_rate is not None:
521 value_json = ['map', [['max-rate', max_rate]]]
522 self.set_column(ovsrec_qos, 'other_config', value_json)
523 self.add_qos_to_cache(vsctl_port, [ovsrec_qos])
526 def set_queue(self, vsctl_qos, max_rate, min_rate,
529 ovsrec_qos = vsctl_qos.qos_cfg[0]
531 ovsrec_queue = ovsrec_qos.queues[queue_id]
532 except (AttributeError, KeyError):
533 ovsrec_queue = self.txn.insert(
534 self.txn.idl.tables[vswitch_idl.OVSREC_TABLE_QUEUE])
535 if max_rate is not None:
536 value_json = ['map', [['max-rate', max_rate]]]
537 self.add_column(ovsrec_queue, 'other_config', value_json)
538 if min_rate is not None:
539 value_json = ['map', [['min-rate', min_rate]]]
540 self.add_column(ovsrec_queue, 'other_config', value_json)
541 value_json = ['map', [[queue_id, ['uuid', str(ovsrec_queue.uuid)]]]]
542 self.add_column(ovsrec_qos, 'queues', value_json)
543 self.add_queue_to_cache(vsctl_qos, ovsrec_queue)
547 def _column_set(ovsrec_row, column, ovsrec_value):
548 # need to trigger Row.__setattr__()
549 setattr(ovsrec_row, column, ovsrec_value)
552 def _column_insert(ovsrec_row, column, ovsrec_add):
553 value = getattr(ovsrec_row, column)
554 value.append(ovsrec_add)
555 VSCtlContext._column_set(ovsrec_row, column, value)
558 def _column_delete(ovsrec_row, column, ovsrec_del):
559 value = getattr(ovsrec_row, column)
561 value.remove(ovsrec_del)
563 # Datum.to_python() with _uuid_to_row trims down deleted
564 # references. If ovsrec_del.delete() is called before
565 # _column_delete(), value doesn't include ovsrec_del.
568 VSCtlContext._column_set(ovsrec_row, column, value)
571 def bridge_insert_port(ovsrec_bridge, ovsrec_port):
572 VSCtlContext._column_insert(ovsrec_bridge,
573 vswitch_idl.OVSREC_BRIDGE_COL_PORTS,
577 def bridge_delete_port(ovsrec_bridge, ovsrec_port):
578 VSCtlContext._column_delete(ovsrec_bridge,
579 vswitch_idl.OVSREC_BRIDGE_COL_PORTS,
583 def port_delete_qos(ovsrec_port, ovsrec_qos):
584 VSCtlContext._column_delete(ovsrec_port,
585 vswitch_idl.OVSREC_PORT_COL_QOS,
588 def ovs_insert_bridge(self, ovsrec_bridge):
589 self._column_insert(self.ovs,
590 vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
593 def ovs_delete_bridge(self, ovsrec_bridge):
594 self._column_delete(self.ovs,
595 vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
598 def del_port(self, vsctl_port):
599 if vsctl_port.bridge().parent:
600 ovsrec_bridge = vsctl_port.bridge().parent.br_cfg
602 ovsrec_bridge = vsctl_port.bridge().br_cfg
603 self.bridge_delete_port(ovsrec_bridge, vsctl_port.port_cfg)
605 for vsctl_iface in vsctl_port.ifaces.copy():
606 self.del_cached_iface(vsctl_iface)
607 self.del_cached_port(vsctl_port)
609 def del_bridge(self, vsctl_bridge):
610 for child in vsctl_bridge.children.copy():
611 self.del_bridge(child)
612 for vsctl_port in vsctl_bridge.ports.copy():
613 self.del_port(vsctl_port)
614 self.del_cached_bridge(vsctl_bridge)
616 def del_qos(self, vsctl_qos):
617 ovsrec_port = vsctl_qos.port().port_cfg
618 ovsrec_qos = vsctl_qos.qos_cfg
620 self.port_delete_qos(ovsrec_port, ovsrec_qos[0])
621 self.del_cached_qos(vsctl_qos)
623 def add_port(self, br_name, port_name, may_exist, fake_iface,
624 iface_names, settings=None):
626 :type settings: list of (column, value_json)
628 value_json is json that is represented
631 settings = settings or []
633 self.populate_cache()
635 vsctl_port = self.find_port(port_name, False)
637 want_names = set(iface_names)
638 have_names = set(ovsrec_iface.name for ovsrec_iface in
639 vsctl_port.port_cfg.interfaces)
640 if vsctl_port.bridge().name != br_name:
641 vsctl_fatal('"%s" but %s is actually attached to '
643 (br_name, port_name, vsctl_port.bridge().name))
644 if want_names != have_names:
645 want_names_string = ','.join(want_names)
646 have_names_string = ','.join(have_names)
647 vsctl_fatal('"%s" but %s actually has interface(s) %s' %
649 port_name, have_names_string))
651 self.check_conflicts(port_name,
652 'cannot create a port named %s' % port_name)
653 for iface_name in iface_names:
654 self.check_conflicts(
655 iface_name, 'cannot create an interface named %s' % iface_name)
657 vsctl_bridge = self.find_bridge(br_name, True)
659 for iface_name in iface_names:
660 ovsrec_iface = self.txn.insert(
661 self.idl.tables[vswitch_idl.OVSREC_TABLE_INTERFACE])
662 ovsrec_iface.name = iface_name
663 ifaces.append(ovsrec_iface)
665 ovsrec_port = self.txn.insert(
666 self.idl.tables[vswitch_idl.OVSREC_TABLE_PORT])
667 ovsrec_port.name = port_name
668 ovsrec_port.interfaces = ifaces
669 ovsrec_port.bond_fake_iface = fake_iface
671 if vsctl_bridge.parent:
672 tag = vsctl_bridge.vlan
673 ovsrec_port.tag = tag
674 for column, value in settings:
675 # TODO:XXX self.symtab:
676 self.set_column(ovsrec_port, column, value)
678 if vsctl_bridge.parent:
679 ovsrec_bridge = vsctl_bridge.parent.br_cfg
681 ovsrec_bridge = vsctl_bridge.br_cfg
682 self.bridge_insert_port(ovsrec_bridge, ovsrec_port)
683 vsctl_port = self.add_port_to_cache(vsctl_bridge, ovsrec_port)
684 for ovsrec_iface in ifaces:
685 self.add_iface_to_cache(vsctl_port, ovsrec_iface)
687 def add_bridge(self, br_name, parent_name=None, vlan=0, may_exist=False):
688 self.populate_cache()
690 vsctl_bridge = self.find_bridge(br_name, False)
693 if vsctl_bridge.parent:
694 vsctl_fatal('"--may-exist add-vsctl_bridge %s" '
695 'but %s is a VLAN bridge for VLAN %d' %
696 (br_name, br_name, vsctl_bridge.vlan))
698 if not vsctl_bridge.parent:
699 vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
700 'but %s is not a VLAN bridge' %
701 (br_name, parent_name, vlan, br_name))
702 elif vsctl_bridge.parent.name != parent_name:
703 vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
704 'but %s has the wrong parent %s' %
705 (br_name, parent_name, vlan,
706 br_name, vsctl_bridge.parent.name))
707 elif vsctl_bridge.vlan != vlan:
708 vsctl_fatal('"--may-exist add-vsctl_bridge %s %s %d" '
709 'but %s is a VLAN bridge for the wrong '
711 (br_name, parent_name, vlan, br_name,
715 self.check_conflicts(br_name,
716 'cannot create a bridge named %s' % br_name)
719 tables = self.idl.tables
721 ovsrec_iface = txn.insert(
722 tables[vswitch_idl.OVSREC_TABLE_INTERFACE])
723 ovsrec_iface.name = br_name
724 ovsrec_iface.type = 'internal'
726 ovsrec_port = txn.insert(tables[vswitch_idl.OVSREC_TABLE_PORT])
727 ovsrec_port.name = br_name
728 ovsrec_port.interfaces = [ovsrec_iface]
729 ovsrec_port.fake_bridge = False
731 ovsrec_bridge = txn.insert(tables[vswitch_idl.OVSREC_TABLE_BRIDGE])
732 ovsrec_bridge.name = br_name
733 ovsrec_bridge.ports = [ovsrec_port]
735 self.ovs_insert_bridge(ovsrec_bridge)
737 parent = self.find_bridge(parent_name, False)
738 if parent and parent.parent:
739 vsctl_fatal('cannot create bridge with fake bridge as parent')
741 vsctl_fatal('parent bridge %s does not exist' % parent_name)
743 ovsrec_iface = txn.insert(
744 tables[vswitch_idl.OVSREC_TABLE_INTERFACE])
745 ovsrec_iface.name = br_name
746 ovsrec_iface.type = 'internal'
748 ovsrec_port = txn.insert(tables[vswitch_idl.OVSREC_TABLE_PORT])
749 ovsrec_port.name = br_name
750 ovsrec_port.interfaces = [ovsrec_iface]
751 ovsrec_port.fake_bridge = True
752 ovsrec_port.tag = vlan
754 self.bridge_insert_port(parent.br_cfg, ovsrec_port)
756 self.invalidate_cache()
759 def parse_column_key(setting_string):
761 Parses 'setting_string' as str formatted in <column>[:<key>]
762 and returns str type 'column' and 'key'
764 if ':' in setting_string:
765 # splits <column>:<key> into <column> and <key>
766 column, key = setting_string.split(':', 1)
768 # stores <column> and <value>=None
769 column = setting_string
775 def parse_column_key_value(table_schema, setting_string):
777 Parses 'setting_string' as str formatted in <column>[:<key>]=<value>
778 and returns str type 'column' and json formatted 'value'
780 if ':' in setting_string:
781 # splits <column>:<key>=<value> into <column> and <key>=<value>
782 column, value = setting_string.split(':', 1)
783 elif '=' in setting_string:
784 # splits <column>=<value> into <column> and <value>
785 column, value = setting_string.split('=', 1)
787 # stores <column> and <value>=None
788 column = setting_string
791 if value is not None:
792 type_ = table_schema.columns[column].type
793 value = datum_from_string(type_, value)
797 def get_column(self, ovsrec_row, column, key=None, if_exists=False):
798 value = getattr(ovsrec_row, column, None)
799 if isinstance(value, dict) and key is not None:
800 value = value.get(key, None)
801 column = '%s:%s' % (column, key)
806 vsctl_fatal('%s does not contain a column whose name matches "%s"'
807 % (ovsrec_row._table.name, column))
811 def _pre_mod_column(self, ovsrec_row, column, value_json):
812 if column not in ovsrec_row._table.columns:
813 vsctl_fatal('%s does not contain a column whose name matches "%s"'
814 % (ovsrec_row._table.name, column))
816 column_schema = ovsrec_row._table.columns[column]
817 datum = ovs.db.data.Datum.from_json(
818 column_schema.type, value_json, self.symtab)
819 return datum.to_python(ovs.db.idl._uuid_to_row)
821 def set_column(self, ovsrec_row, column, value_json):
822 column_schema = ovsrec_row._table.columns[column]
823 datum = self._pre_mod_column(ovsrec_row, column, value_json)
825 if column_schema.type.is_map():
826 values = getattr(ovsrec_row, column, {})
831 setattr(ovsrec_row, column, values)
833 def add_column(self, ovsrec_row, column, value_json):
834 column_schema = ovsrec_row._table.columns[column]
835 datum = self._pre_mod_column(ovsrec_row, column, value_json)
837 if column_schema.type.is_map():
838 values = getattr(ovsrec_row, column, {})
840 elif column_schema.type.is_set():
841 values = getattr(ovsrec_row, column, [])
846 setattr(ovsrec_row, column, values)
848 def remove_column(self, ovsrec_row, column, value_json):
849 column_schema = ovsrec_row._table.columns[column]
850 datum = self._pre_mod_column(ovsrec_row, column, value_json)
852 if column_schema.type.is_map():
853 values = getattr(ovsrec_row, column, {})
854 for datum_key, datum_value in datum.items():
855 v = values.get(datum_key, None)
857 values.pop(datum_key)
858 setattr(ovsrec_row, column, values)
859 elif column_schema.type.is_set():
860 values = getattr(ovsrec_row, column, [])
864 setattr(ovsrec_row, column, values)
866 values = getattr(ovsrec_row, column, None)
867 default = ovs.db.data.Datum.default(column_schema.type)
868 default = default.to_python(ovs.db.idl._uuid_to_row).to_json()
870 setattr(ovsrec_row, column, default)
872 def _get_row_by_id(self, table_name, vsctl_row_id, record_id):
873 if not vsctl_row_id.table:
876 if not vsctl_row_id.name_column:
879 values = list(self.idl.tables[vsctl_row_id.table].rows.values())
880 if not values or len(values) > 2:
885 for ovsrec_row in self.idl.tables[
886 vsctl_row_id.table].rows.values():
887 name = getattr(ovsrec_row, vsctl_row_id.name_column)
888 assert isinstance(name, (list, str, six.text_type))
889 if not isinstance(name, list) and name == record_id:
891 vsctl_fatal('multiple rows in %s match "%s"' %
892 (table_name, record_id))
893 referrer = ovsrec_row
899 if vsctl_row_id.uuid_column:
900 referrer.verify(vsctl_row_id.uuid_column)
901 uuid = getattr(referrer, vsctl_row_id.uuid_column)
903 uuid_ = referrer._data[vsctl_row_id.uuid_column]
904 assert uuid_.type.key.type == ovs.db.types.UuidType
905 assert uuid_.type.value is None
906 assert isinstance(uuid, list)
915 def get_row(self, vsctl_table, record_id):
916 table_name = vsctl_table.table_name
917 if ovsuuid.is_valid_string(record_id):
918 uuid = ovsuuid.from_string(record_id)
919 return self.idl.tables[table_name].rows.get(uuid)
921 for vsctl_row_id in vsctl_table.row_ids:
922 ovsrec_row = self._get_row_by_id(table_name, vsctl_row_id,
929 def must_get_row(self, vsctl_table, record_id):
930 ovsrec_row = self.get_row(vsctl_table, record_id)
932 vsctl_fatal('no row "%s" in table %s' % (record_id,
933 vsctl_table.table_name))
937 class _CmdShowTable(object):
939 def __init__(self, table, name_column, columns, recurse):
940 super(_CmdShowTable, self).__init__()
942 self.name_column = name_column
943 self.columns = columns
944 self.recurse = recurse
947 class _VSCtlRowID(object):
949 def __init__(self, table, name_column, uuid_column):
950 super(_VSCtlRowID, self).__init__()
952 self.name_column = name_column
953 self.uuid_column = uuid_column
956 class _VSCtlTable(object):
958 def __init__(self, table_name, vsctl_row_id_list):
959 super(_VSCtlTable, self).__init__()
960 self.table_name = table_name
961 self.row_ids = vsctl_row_id_list
964 class VSCtlCommand(StringifyMixin):
966 Class to describe artgumens similar to those of ``ovs-vsctl`` command.
968 ``command`` specifies the command of ``ovs-vsctl``.
970 ``args`` specifies a list or tuple of arguments for the given command.
972 ``options`` specifies a list or tuple of options for the given command.
973 Please note that NOT all options of ``ovs-vsctl`` are supported.
974 For example, ``--id`` option is not yet supported.
975 This class supports the followings.
977 ================= =========================================================
979 ================= =========================================================
980 ``--may-exist`` Does nothing when the given port already exists.
981 The supported commands are ``add-port`` and
983 ``--fake-iface`` Creates a port as a fake interface.
984 The supported command is ``add-bond``.
985 ``--must-exist`` Raises exception if the given port does not exist.
986 The supported command is ``del-port``.
987 ``--with-iface`` Takes effect to the interface which has the same name.
988 The supported command is ``del-port``.
989 ``--if-exists`` Ignores exception when not found.
990 The supported command is ``get``.
991 ================= =========================================================
994 def __init__(self, command, args=None, options=None):
995 super(VSCtlCommand, self).__init__()
996 self.command = command
997 self.args = args or []
998 self.options = options or []
1000 # Data modified by commands
1003 # internally used by VSCtl
1004 self._prerequisite = None
1007 def has_option(self, option):
1008 return option in self.options
1011 class VSCtl(object):
1013 A class to describe an Open vSwitch instance.
1015 ``remote`` specifies the address of the OVS instance.
1016 :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` is a convenient function to
1017 validate this address.
1021 self.schema_helper = None
1024 self.wait_for_reload = True
1025 self.dry_run = False
1027 def __init__(self, remote):
1028 super(VSCtl, self).__init__()
1029 self.remote = remote
1031 self.schema_json = None
1033 self.schema_helper = None
1036 self.wait_for_reload = True
1037 self.dry_run = False
1039 def _rpc_get_schema_json(self, database):
1040 LOG.debug('remote %s', self.remote)
1041 error, stream_ = stream.Stream.open_block(
1042 stream.Stream.open(self.remote))
1044 vsctl_fatal('error %s' % os.strerror(error))
1045 rpc = jsonrpc.Connection(stream_)
1046 request = jsonrpc.Message.create_request('get_schema', [database])
1047 error, reply = rpc.transact_block(request)
1051 vsctl_fatal(os.strerror(error))
1053 vsctl_fatal('error %s' % reply.error)
1056 def _init_schema_helper(self):
1057 if self.schema_json is None:
1058 self.schema_json = self._rpc_get_schema_json(
1059 vswitch_idl.OVSREC_DB_NAME)
1060 schema_helper = idl.SchemaHelper(None, self.schema_json)
1061 schema_helper.register_all()
1062 self.schema = schema_helper.get_idl_schema()
1063 # LOG.debug('schema_json %s', schema_json)
1064 self.schema_helper = idl.SchemaHelper(None, self.schema_json)
1067 def _idl_block(idl_):
1068 poller = ovs.poller.Poller()
1073 def _idl_wait(idl_, seqno):
1074 while idl_.change_seqno == seqno and not idl_.run():
1075 VSCtl._idl_block(idl_)
1077 def _run_prerequisites(self, commands):
1078 schema_helper = self.schema_helper
1079 schema_helper.register_table(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH)
1080 if self.wait_for_reload:
1081 # LOG.debug('schema_helper._tables %s', schema_helper._tables)
1082 schema_helper.register_columns(
1083 vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH,
1084 [vswitch_idl.OVSREC_OPEN_VSWITCH_COL_CUR_CFG])
1086 for command in commands:
1087 if not command._prerequisite:
1089 ctx = VSCtlContext(None, None, None)
1090 command._prerequisite(ctx, command)
1093 def _do_vsctl(self, idl_, commands):
1094 self.txn = idl.Transaction(idl_)
1096 self.txn.dry_run = True
1098 self.txn.add_comment('ovs-vsctl') # TODO:XXX add operation name. args
1099 ovs_rows = idl_.tables[vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH].rows
1101 ovs_ = list(ovs_rows.values())[0]
1103 # XXX add verification that table is empty
1104 ovs_ = self.txn.insert(
1105 idl_.tables[vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH])
1107 if self.wait_for_reload:
1108 ovs_.increment(vswitch_idl.OVSREC_OPEN_VSWITCH_COL_NEXT_CFG)
1111 # symtab = ovsdb_symbol_table_create()
1112 ctx = VSCtlContext(idl_, self.txn, ovs_)
1113 for command in commands:
1114 if not command._run:
1116 command._run(ctx, command)
1119 LOG.debug('result:\n%s', [command.result for command in commands])
1122 # TODO:XXX check if created symbols are really created, referenced.
1124 status = self.txn.commit_block()
1126 if self.wait_for_reload and status == idl.Transaction.SUCCESS:
1127 next_cfg = self.txn.get_increment_new_value()
1130 # if status in (idl.Transaction.UNCHANGED, idl.Transaction.SUCCESS):
1131 # for command in commands:
1132 # if not command.post_func:
1134 # ctx = VSCtlContext(idl_, txn, self.ovs)
1135 # command.post_func(ctx)
1141 if status in (idl.Transaction.UNCOMMITTED, idl.Transaction.INCOMPLETE):
1143 elif status == idl.Transaction.ABORTED:
1144 vsctl_fatal('transaction aborted')
1145 elif status == idl.Transaction.UNCHANGED:
1146 LOG.debug('unchanged')
1147 elif status == idl.Transaction.SUCCESS:
1148 LOG.debug('success')
1149 elif status == idl.Transaction.TRY_AGAIN:
1151 elif status == idl.Transaction.ERROR:
1152 vsctl_fatal('transaction error: %s' % txn_.get_error())
1153 elif status == idl.Transaction.NOT_LOCKED:
1154 vsctl_fatal('database not locked')
1158 if self.wait_for_reload and status != idl.Transaction.UNCHANGED:
1161 if ovs_.cur_cfg >= next_cfg:
1163 self._idl_block(idl_)
1167 def _do_main(self, commands):
1169 :type commands: list of VSCtlCommand
1172 self._init_schema_helper()
1173 self._run_prerequisites(commands)
1175 idl_ = idl.Idl(self.remote, self.schema_helper)
1176 seqno = idl_.change_seqno
1178 self._idl_wait(idl_, seqno)
1180 seqno = idl_.change_seqno
1181 if self._do_vsctl(idl_, commands):
1188 # ovsdb_symbol_table_destroy(symtab)
1192 def _run_command(self, commands):
1194 :type commands: list of VSCtlCommand
1197 # Open vSwitch commands.
1198 'init': (None, self._cmd_init),
1199 'show': (self._pre_cmd_show, self._cmd_show),
1203 'add-br': (self._pre_add_br, self._cmd_add_br),
1204 'del-br': (self._pre_get_info, self._cmd_del_br),
1205 'list-br': (self._pre_get_info, self._cmd_list_br),
1206 'br-exists': (self._pre_get_info, self._cmd_br_exists),
1207 'br-to-vlan': (self._pre_get_info, self._cmd_br_to_vlan),
1208 'br-to-parent': (self._pre_get_info, self._cmd_br_to_parent),
1209 'br-set-external-id': (self._pre_cmd_br_set_external_id,
1210 self._cmd_br_set_external_id),
1211 'br-get-external-id': (self._pre_cmd_br_get_external_id,
1212 self._cmd_br_get_external_id),
1215 'list-ports': (self._pre_get_info, self._cmd_list_ports),
1216 'add-port': (self._pre_cmd_add_port, self._cmd_add_port),
1217 'add-bond': (self._pre_cmd_add_bond, self._cmd_add_bond),
1218 'del-port': (self._pre_get_info, self._cmd_del_port),
1219 'port-to-br': (self._pre_get_info, self._cmd_port_to_br),
1221 # Interface commands.
1222 'list-ifaces': (self._pre_get_info, self._cmd_list_ifaces),
1223 'iface-to-br': (self._pre_get_info, self._cmd_iface_to_br),
1225 # Controller commands.
1226 'get-controller': (self._pre_controller, self._cmd_get_controller),
1227 'del-controller': (self._pre_controller, self._cmd_del_controller),
1228 'set-controller': (self._pre_controller, self._cmd_set_controller),
1229 'get-fail-mode': (self._pre_fail_mode, self._cmd_get_fail_mode),
1230 'del-fail-mode': (self._pre_fail_mode, self._cmd_del_fail_mode),
1231 'set-fail-mode': (self._pre_fail_mode, self._cmd_set_fail_mode),
1243 # Auto Attach commands.
1251 # Database commands.
1252 'list': (self._pre_cmd_list, self._cmd_list),
1253 'find': (self._pre_cmd_find, self._cmd_find),
1254 'get': (self._pre_cmd_get, self._cmd_get),
1255 'set': (self._pre_cmd_set, self._cmd_set),
1256 'add': (self._pre_cmd_add, self._cmd_add),
1257 'remove': (self._pre_cmd_remove, self._cmd_remove),
1258 'clear': (self._pre_cmd_clear, self._cmd_clear),
1263 # Utility commands. (No corresponding command in ovs-vsctl)
1264 'set-qos': (self._pre_cmd_set_qos, self._cmd_set_qos),
1265 'set-queue': (self._pre_cmd_set_queue, self._cmd_set_queue),
1266 'del-qos': (self._pre_get_info, self._cmd_del_qos),
1267 # for quantum_adapter
1268 'list-ifaces-verbose': (self._pre_cmd_list_ifaces_verbose,
1269 self._cmd_list_ifaces_verbose),
1272 for command in commands:
1273 funcs = all_commands[command.command]
1274 command._prerequisite, command._run = funcs
1275 self._do_main(commands)
1277 def run_command(self, commands, timeout_sec=None, exception=None):
1279 Executes the given commands and sends OVSDB messages.
1281 ``commands`` must be a list of
1282 :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
1284 If ``timeout_sec`` is specified, raises exception after the given
1285 timeout [sec]. Additionally, if ``exception`` is specified, this
1286 function will wraps exception using the given exception class.
1288 Retruns ``None`` but fills ``result`` attribute for each command
1291 if timeout_sec is None:
1292 self._run_command(commands)
1294 with hub.Timeout(timeout_sec, exception):
1295 self._run_command(commands)
1297 # Open vSwitch commands:
1299 def _cmd_init(self, _ctx, _command):
1300 # nothing. Just check connection to ovsdb
1303 _CMD_SHOW_TABLES = [
1304 _CmdShowTable(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH, None,
1305 [vswitch_idl.OVSREC_OPEN_VSWITCH_COL_MANAGER_OPTIONS,
1306 vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES,
1307 vswitch_idl.OVSREC_OPEN_VSWITCH_COL_OVS_VERSION],
1309 _CmdShowTable(vswitch_idl.OVSREC_TABLE_BRIDGE,
1310 vswitch_idl.OVSREC_BRIDGE_COL_NAME,
1311 [vswitch_idl.OVSREC_BRIDGE_COL_CONTROLLER,
1312 vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE,
1313 vswitch_idl.OVSREC_BRIDGE_COL_PORTS],
1315 _CmdShowTable(vswitch_idl.OVSREC_TABLE_PORT,
1316 vswitch_idl.OVSREC_PORT_COL_NAME,
1317 [vswitch_idl.OVSREC_PORT_COL_TAG,
1318 vswitch_idl.OVSREC_PORT_COL_TRUNKS,
1319 vswitch_idl.OVSREC_PORT_COL_INTERFACES],
1321 _CmdShowTable(vswitch_idl.OVSREC_TABLE_INTERFACE,
1322 vswitch_idl.OVSREC_INTERFACE_COL_NAME,
1323 [vswitch_idl.OVSREC_INTERFACE_COL_TYPE,
1324 vswitch_idl.OVSREC_INTERFACE_COL_OPTIONS],
1326 _CmdShowTable(vswitch_idl.OVSREC_TABLE_CONTROLLER,
1327 vswitch_idl.OVSREC_CONTROLLER_COL_TARGET,
1328 [vswitch_idl.OVSREC_CONTROLLER_COL_IS_CONNECTED],
1330 _CmdShowTable(vswitch_idl.OVSREC_TABLE_MANAGER,
1331 vswitch_idl.OVSREC_MANAGER_COL_TARGET,
1332 [vswitch_idl.OVSREC_MANAGER_COL_IS_CONNECTED],
1336 def _pre_cmd_show(self, _ctx, _command):
1337 schema_helper = self.schema_helper
1338 for show in self._CMD_SHOW_TABLES:
1339 schema_helper.register_table(show.table)
1340 if show.name_column:
1341 schema_helper.register_columns(show.table, [show.name_column])
1342 schema_helper.register_columns(show.table, show.columns)
1345 def _cmd_show_find_table_by_row(row):
1346 for show in VSCtl._CMD_SHOW_TABLES:
1347 if show.table == row._table.name:
1352 def _cmd_show_find_table_by_name(name):
1353 for show in VSCtl._CMD_SHOW_TABLES:
1354 if show.table == name:
1359 def _cmd_show_row(ctx, row, level):
1360 _INDENT_SIZE = 4 # # of spaces per indent
1361 show = VSCtl._cmd_show_find_table_by_row(row)
1364 output += ' ' * level * _INDENT_SIZE
1365 if show and show.name_column:
1366 output += '%s ' % show.table
1367 datum = getattr(row, show.name_column)
1370 output += str(row.uuid)
1373 if not show or show.recurse:
1377 for column in show.columns:
1378 datum = row._data[column]
1379 key = datum.type.key
1380 if key.type == ovs.db.types.UuidType and key.ref_table_name:
1381 ref_show = VSCtl._cmd_show_find_table_by_name(
1384 for atom in datum.values:
1385 ref_row = ctx.idl.tables[ref_show.table].rows.get(
1388 VSCtl._cmd_show_row(ctx, ref_row, level + 1)
1391 if not datum.is_default():
1392 output += ' ' * (level + 1) * _INDENT_SIZE
1393 output += '%s: %s\n' % (column, datum)
1395 show.recurse = False
1398 def _cmd_show(self, ctx, command):
1399 for row in ctx.idl.tables[
1400 self._CMD_SHOW_TABLES[0].table].rows.values():
1401 output = self._cmd_show_row(ctx, row, 0)
1402 command.result = output
1406 def _pre_get_info(self, _ctx, _command):
1407 schema_helper = self.schema_helper
1409 schema_helper.register_columns(
1410 vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH,
1411 [vswitch_idl.OVSREC_OPEN_VSWITCH_COL_BRIDGES])
1412 schema_helper.register_columns(
1413 vswitch_idl.OVSREC_TABLE_BRIDGE,
1414 [vswitch_idl.OVSREC_BRIDGE_COL_NAME,
1415 vswitch_idl.OVSREC_BRIDGE_COL_CONTROLLER,
1416 vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE,
1417 vswitch_idl.OVSREC_BRIDGE_COL_PORTS])
1418 schema_helper.register_columns(
1419 vswitch_idl.OVSREC_TABLE_PORT,
1420 [vswitch_idl.OVSREC_PORT_COL_NAME,
1421 vswitch_idl.OVSREC_PORT_COL_FAKE_BRIDGE,
1422 vswitch_idl.OVSREC_PORT_COL_TAG,
1423 vswitch_idl.OVSREC_PORT_COL_INTERFACES,
1424 vswitch_idl.OVSREC_PORT_COL_QOS])
1425 schema_helper.register_columns(
1426 vswitch_idl.OVSREC_TABLE_INTERFACE,
1427 [vswitch_idl.OVSREC_INTERFACE_COL_NAME])
1428 schema_helper.register_columns(
1429 vswitch_idl.OVSREC_TABLE_QOS,
1430 [vswitch_idl.OVSREC_QOS_COL_QUEUES])
1431 schema_helper.register_columns(
1432 vswitch_idl.OVSREC_TABLE_QUEUE,
1435 def _cmd_list_br(self, ctx, command):
1436 ctx.populate_cache()
1437 command.result = sorted(ctx.bridges.keys())
1439 def _pre_add_br(self, ctx, command):
1440 self._pre_get_info(ctx, command)
1442 schema_helper = self.schema_helper
1443 schema_helper.register_columns(
1444 vswitch_idl.OVSREC_TABLE_INTERFACE,
1445 [vswitch_idl.OVSREC_INTERFACE_COL_TYPE])
1447 def _cmd_add_br(self, ctx, command):
1448 br_name = command.args[0]
1451 if len(command.args) == 1:
1453 elif len(command.args) == 3:
1454 parent_name = command.args[1]
1455 vlan = int(command.args[2])
1456 if vlan < 0 or vlan > 4095:
1457 vsctl_fatal("vlan must be between 0 and 4095 %d" % vlan)
1459 vsctl_fatal('this command takes exactly 1 or 3 argument')
1461 ctx.add_bridge(br_name, parent_name, vlan)
1463 def _del_br(self, ctx, br_name, must_exist=False):
1464 ctx.populate_cache()
1465 br = ctx.find_bridge(br_name, must_exist)
1469 def _cmd_del_br(self, ctx, command):
1470 br_name = command.args[0]
1471 self._del_br(ctx, br_name)
1473 def _br_exists(self, ctx, br_name):
1474 ctx.populate_cache()
1475 br = ctx.find_bridge(br_name, must_exist=False)
1476 return br is not None
1478 def _cmd_br_exists(self, ctx, command):
1479 br_name = command.args[0]
1480 command.result = self._br_exists(ctx, br_name)
1482 def _br_to_vlan(self, ctx, br_name):
1483 ctx.populate_cache()
1484 br = ctx.find_bridge(br_name, must_exist=True)
1486 if isinstance(vlan, list):
1493 def _cmd_br_to_vlan(self, ctx, command):
1494 br_name = command.args[0]
1495 command.result = self._br_to_vlan(ctx, br_name)
1497 def _br_to_parent(self, ctx, br_name):
1498 ctx.populate_cache()
1499 br = ctx.find_bridge(br_name, must_exist=True)
1500 return br if br.parent is None else br.parent
1502 def _cmd_br_to_parent(self, ctx, command):
1503 br_name = command.args[0]
1504 command.result = self._br_to_parent(ctx, br_name)
1506 def _pre_cmd_br_set_external_id(self, ctx, _command):
1507 table_name = vswitch_idl.OVSREC_TABLE_BRIDGE
1508 columns = [vswitch_idl.OVSREC_BRIDGE_COL_EXTERNAL_IDS]
1509 self._pre_mod_columns(ctx, table_name, columns)
1511 def _br_add_external_id(self, ctx, br_name, key, value):
1512 table_name = vswitch_idl.OVSREC_TABLE_BRIDGE
1513 column = vswitch_idl.OVSREC_BRIDGE_COL_EXTERNAL_IDS
1514 vsctl_table = self._get_table(table_name)
1515 ovsrec_row = ctx.must_get_row(vsctl_table, br_name)
1517 value_json = ['map', [[key, value]]]
1518 ctx.add_column(ovsrec_row, column, value_json)
1519 ctx.invalidate_cache()
1521 def _br_clear_external_id(self, ctx, br_name, key):
1522 table_name = vswitch_idl.OVSREC_TABLE_BRIDGE
1523 column = vswitch_idl.OVSREC_BRIDGE_COL_EXTERNAL_IDS
1524 vsctl_table = self._get_table(table_name)
1525 ovsrec_row = ctx.must_get_row(vsctl_table, br_name)
1527 values = getattr(ovsrec_row, column, {})
1528 values.pop(key, None)
1529 setattr(ovsrec_row, column, values)
1530 ctx.invalidate_cache()
1532 def _cmd_br_set_external_id(self, ctx, command):
1533 br_name = command.args[0]
1534 key = command.args[1]
1535 if len(command.args) > 2:
1536 self._br_add_external_id(ctx, br_name, key, command.args[2])
1538 self._br_clear_external_id(ctx, br_name, key)
1540 def _pre_cmd_br_get_external_id(self, ctx, _command):
1541 table_name = vswitch_idl.OVSREC_TABLE_BRIDGE
1542 columns = [vswitch_idl.OVSREC_BRIDGE_COL_EXTERNAL_IDS]
1543 self._pre_get_columns(ctx, table_name, columns)
1545 def _br_get_external_id_value(self, ctx, br_name, key):
1546 external_id = self._br_get_external_id_list(ctx, br_name)
1548 return external_id.get(key, None)
1550 def _br_get_external_id_list(self, ctx, br_name):
1551 table_name = vswitch_idl.OVSREC_TABLE_BRIDGE
1552 column = vswitch_idl.OVSREC_BRIDGE_COL_EXTERNAL_IDS
1553 vsctl_table = self._get_table(table_name)
1554 ovsrec_row = ctx.must_get_row(vsctl_table, br_name)
1556 return ctx.get_column(ovsrec_row, column)
1558 def _cmd_br_get_external_id(self, ctx, command):
1559 br_name = command.args[0]
1560 if len(command.args) > 1:
1561 command.result = self._br_get_external_id_value(ctx, br_name,
1564 command.result = self._br_get_external_id_list(ctx, br_name)
1568 def _list_ports(self, ctx, br_name):
1569 ctx.populate_cache()
1570 br = ctx.find_bridge(br_name, True)
1572 br.br_cfg.verify(vswitch_idl.OVSREC_BRIDGE_COL_PORTS)
1574 br.parent.br_cfg.verify(vswitch_idl.OVSREC_BRIDGE_COL_PORTS)
1576 return [port.port_cfg.name for port in br.ports
1577 if port.port_cfg.name != br.name]
1579 def _cmd_list_ports(self, ctx, command):
1580 br_name = command.args[0]
1581 port_names = self._list_ports(ctx, br_name)
1582 command.result = sorted(port_names)
1584 def _pre_add_port(self, _ctx, columns):
1585 schema_helper = self.schema_helper
1586 schema_helper.register_columns(
1587 vswitch_idl.OVSREC_TABLE_PORT,
1588 [vswitch_idl.OVSREC_PORT_COL_NAME,
1589 vswitch_idl.OVSREC_PORT_COL_BOND_FAKE_IFACE])
1590 schema_helper.register_columns(
1591 vswitch_idl.OVSREC_TABLE_PORT, columns)
1593 def _pre_cmd_add_port(self, ctx, command):
1594 self._pre_get_info(ctx, command)
1597 ctx.parse_column_key_value(
1598 self.schema.tables[vswitch_idl.OVSREC_TABLE_PORT], setting)[0]
1599 for setting in command.args[2:]]
1601 self._pre_add_port(ctx, columns)
1603 def _pre_cmd_add_bond(self, ctx, command):
1604 self._pre_get_info(ctx, command)
1606 if len(command.args) < 3:
1607 vsctl_fatal('this command requires at least 3 arguments')
1610 ctx.parse_column_key_value(
1611 self.schema.tables[vswitch_idl.OVSREC_TABLE_PORT], setting)[0]
1612 for setting in command.args[3:]]
1614 self._pre_add_port(ctx, columns)
1616 def _cmd_add_port(self, ctx, command):
1617 # '--may_exist' is a typo but for backword compatibility
1618 may_exist = (command.has_option('--may_exist')
1619 or command.has_option('--may-exist'))
1621 br_name = command.args[0]
1622 port_name = command.args[1]
1623 iface_names = [command.args[1]]
1625 ctx.parse_column_key_value(
1626 self.schema.tables[vswitch_idl.OVSREC_TABLE_PORT], setting)
1627 for setting in command.args[2:]]
1629 ctx.add_port(br_name, port_name, may_exist,
1630 False, iface_names, settings)
1632 def _cmd_add_bond(self, ctx, command):
1633 # '--may_exist' is a typo but for backword compatibility
1634 may_exist = (command.has_option('--may_exist')
1635 or command.has_option('--may-exist'))
1636 fake_iface = command.has_option('--fake-iface')
1638 br_name = command.args[0]
1639 port_name = command.args[1]
1640 iface_names = list(command.args[2])
1642 ctx.parse_column_key_value(
1643 self.schema.tables[vswitch_idl.OVSREC_TABLE_PORT], setting)
1644 for setting in command.args[3:]]
1646 ctx.add_port(br_name, port_name, may_exist, fake_iface,
1647 iface_names, settings)
1649 def _del_port(self, ctx, br_name=None, target=None,
1650 must_exist=False, with_iface=False):
1651 assert target is not None
1653 ctx.populate_cache()
1655 vsctl_port = ctx.find_port(target, must_exist)
1657 vsctl_port = ctx.find_port(target, False)
1659 vsctl_iface = ctx.find_iface(target, False)
1661 vsctl_port = vsctl_iface.port()
1662 if must_exist and not vsctl_port:
1663 vsctl_fatal('no port or interface named %s' % target)
1668 vsctl_bridge = ctx.find_bridge(br_name, True)
1669 if vsctl_port.bridge() != vsctl_bridge:
1670 if vsctl_port.bridge().parent == vsctl_bridge:
1671 vsctl_fatal('bridge %s does not have a port %s (although '
1672 'its parent bridge %s does)' %
1673 (br_name, target, vsctl_bridge.parent.name))
1675 vsctl_fatal('bridge %s does not have a port %s' %
1678 ctx.del_port(vsctl_port)
1680 def _cmd_del_port(self, ctx, command):
1681 must_exist = command.has_option('--must-exist')
1682 with_iface = command.has_option('--with-iface')
1683 target = command.args[-1]
1684 br_name = command.args[0] if len(command.args) == 2 else None
1685 self._del_port(ctx, br_name, target, must_exist, with_iface)
1687 def _port_to_br(self, ctx, port_name):
1688 ctx.populate_cache()
1689 port = ctx.find_port(port_name, True)
1690 bridge = port.bridge()
1692 vsctl_fatal('Bridge associated to port "%s" does not exist' %
1697 def _cmd_port_to_br(self, ctx, command):
1698 iface_name = command.args[0]
1699 command.result = self._iface_to_br(ctx, iface_name)
1701 # Interface commands:
1703 def _list_ifaces(self, ctx, br_name):
1704 ctx.populate_cache()
1706 br = ctx.find_bridge(br_name, True)
1710 for vsctl_port in br.ports:
1711 for vsctl_iface in vsctl_port.ifaces:
1712 iface_name = vsctl_iface.iface_cfg.name
1713 if iface_name != br_name:
1714 iface_names.add(iface_name)
1717 def _cmd_list_ifaces(self, ctx, command):
1718 br_name = command.args[0]
1719 iface_names = self._list_ifaces(ctx, br_name)
1720 command.result = sorted(iface_names)
1722 def _iface_to_br(self, ctx, iface_name):
1723 ctx.populate_cache()
1724 iface = ctx.find_iface(iface_name, True)
1727 vsctl_fatal('Port associated to iface "%s" does not exist' %
1729 bridge = port.bridge()
1731 vsctl_fatal('Bridge associated to iface "%s" does not exist' %
1736 def _cmd_iface_to_br(self, ctx, command):
1737 iface_name = command.args[0]
1738 command.result = self._iface_to_br(ctx, iface_name)
1740 # Utility commands for quantum_adapter:
1742 def _pre_cmd_list_ifaces_verbose(self, ctx, command):
1743 self._pre_get_info(ctx, command)
1744 schema_helper = self.schema_helper
1745 schema_helper.register_columns(
1746 vswitch_idl.OVSREC_TABLE_BRIDGE,
1747 [vswitch_idl.OVSREC_BRIDGE_COL_DATAPATH_ID])
1748 schema_helper.register_columns(
1749 vswitch_idl.OVSREC_TABLE_INTERFACE,
1750 [vswitch_idl.OVSREC_INTERFACE_COL_TYPE,
1751 vswitch_idl.OVSREC_INTERFACE_COL_NAME,
1752 vswitch_idl.OVSREC_INTERFACE_COL_EXTERNAL_IDS,
1753 vswitch_idl.OVSREC_INTERFACE_COL_OPTIONS,
1754 vswitch_idl.OVSREC_INTERFACE_COL_OFPORT])
1757 def _iface_to_dict(iface_cfg):
1758 _ATTRIBUTE = ['name', 'ofport', 'type', 'external_ids', 'options']
1759 attr = dict((key, getattr(iface_cfg, key)) for key in _ATTRIBUTE)
1762 attr['ofport'] = attr['ofport'][0]
1765 def _list_ifaces_verbose(self, ctx, datapath_id, port_name):
1766 ctx.populate_cache()
1768 br = ctx.find_bridge_by_id(datapath_id, True)
1772 if port_name is None:
1773 for vsctl_port in br.ports:
1774 iface_cfgs.extend(self._iface_to_dict(vsctl_iface.iface_cfg)
1775 for vsctl_iface in vsctl_port.ifaces)
1777 # When port is created, ofport column might be None.
1778 # So try with port name if it happended
1779 for vsctl_port in br.ports:
1781 self._iface_to_dict(vsctl_iface.iface_cfg)
1782 for vsctl_iface in vsctl_port.ifaces
1783 if vsctl_iface.iface_cfg.name == port_name)
1787 def _cmd_list_ifaces_verbose(self, ctx, command):
1788 datapath_id = command.args[0]
1790 if len(command.args) >= 2:
1791 port_name = command.args[1]
1792 LOG.debug('command.args %s', command.args)
1793 iface_cfgs = self._list_ifaces_verbose(ctx, datapath_id, port_name)
1794 command.result = sorted(iface_cfgs)
1796 # Controller commands:
1798 def _verify_controllers(self, ovsrec_bridge):
1799 ovsrec_bridge.verify(vswitch_idl.OVSREC_BRIDGE_COL_CONTROLLER)
1800 for controller in ovsrec_bridge.controller:
1801 controller.verify(vswitch_idl.OVSREC_CONTROLLER_COL_TARGET)
1803 def _pre_controller(self, ctx, command):
1804 self._pre_get_info(ctx, command)
1805 self.schema_helper.register_columns(
1806 vswitch_idl.OVSREC_TABLE_CONTROLLER,
1807 [vswitch_idl.OVSREC_CONTROLLER_COL_TARGET])
1809 def _get_controller(self, ctx, br_name):
1810 ctx.populate_cache()
1811 br = ctx.find_bridge(br_name, True)
1812 self._verify_controllers(br.br_cfg)
1813 return set(controller.target for controller in br.br_cfg.controller)
1815 def _cmd_get_controller(self, ctx, command):
1816 br_name = command.args[0]
1817 controller_names = self._get_controller(ctx, br_name)
1818 command.result = sorted(controller_names)
1820 def _delete_controllers(self, ovsrec_controllers):
1821 for controller in ovsrec_controllers:
1824 def _del_controller(self, ctx, br_name):
1825 ctx.populate_cache()
1826 br = ctx.find_real_bridge(br_name, True)
1827 ovsrec_bridge = br.br_cfg
1828 self._verify_controllers(ovsrec_bridge)
1829 if ovsrec_bridge.controller:
1830 self._delete_controllers(ovsrec_bridge.controller)
1831 ovsrec_bridge.controller = []
1833 def _cmd_del_controller(self, ctx, command):
1834 br_name = command.args[0]
1835 self._del_controller(ctx, br_name)
1837 def _insert_controllers(self, controller_names):
1838 ovsrec_controllers = []
1839 for name in controller_names:
1840 # TODO: check if the name startswith() supported protocols
1841 ovsrec_controller = self.txn.insert(
1842 self.txn.idl.tables[vswitch_idl.OVSREC_TABLE_CONTROLLER])
1843 ovsrec_controller.target = name
1844 ovsrec_controllers.append(ovsrec_controller)
1845 return ovsrec_controllers
1847 def _insert_qos(self):
1848 ovsrec_qos = self.txn.insert(
1849 self.txn.idl.tables[vswitch_idl.OVSREC_TABLE_QOS])
1853 def _set_controller(self, ctx, br_name, controller_names):
1854 ctx.populate_cache()
1855 ovsrec_bridge = ctx.find_real_bridge(br_name, True).br_cfg
1856 self._verify_controllers(ovsrec_bridge)
1857 self._delete_controllers(ovsrec_bridge.controller)
1858 controllers = self._insert_controllers(controller_names)
1859 ovsrec_bridge.controller = controllers
1861 def _cmd_set_controller(self, ctx, command):
1862 br_name = command.args[0]
1863 controller_names = command.args[1:]
1864 self._set_controller(ctx, br_name, controller_names)
1866 def _pre_fail_mode(self, ctx, command):
1867 self._pre_get_info(ctx, command)
1868 self.schema_helper.register_columns(
1869 vswitch_idl.OVSREC_TABLE_BRIDGE,
1870 [vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE])
1872 def _get_fail_mode(self, ctx, br_name):
1873 ctx.populate_cache()
1874 br = ctx.find_bridge(br_name, True)
1876 # Note: Returns first element of fail_mode column
1877 return getattr(br.br_cfg, vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE)[0]
1879 def _cmd_get_fail_mode(self, ctx, command):
1880 br_name = command.args[0]
1881 command.result = self._get_fail_mode(ctx, br_name)
1883 def _del_fail_mode(self, ctx, br_name):
1884 ctx.populate_cache()
1885 br = ctx.find_bridge(br_name, True)
1886 # Note: assuming that [] means empty
1887 setattr(br.br_cfg, vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE, [])
1888 ctx.invalidate_cache()
1890 def _cmd_del_fail_mode(self, ctx, command):
1891 br_name = command.args[0]
1892 self._del_fail_mode(ctx, br_name)
1894 def _set_fail_mode(self, ctx, br_name, mode):
1895 ctx.populate_cache()
1896 br = ctx.find_bridge(br_name, True)
1897 setattr(br.br_cfg, vswitch_idl.OVSREC_BRIDGE_COL_FAIL_MODE, mode)
1898 ctx.invalidate_cache()
1900 def _cmd_set_fail_mode(self, ctx, command):
1901 br_name = command.args[0]
1902 mode = command.args[1]
1903 if mode not in ('standalone', 'secure'):
1904 vsctl_fatal('fail-mode must be "standalone" or "secure"')
1905 self._set_fail_mode(ctx, br_name, mode)
1909 def _del_qos(self, ctx, port_name):
1910 assert port_name is not None
1912 ctx.populate_cache()
1913 vsctl_port = ctx.find_port(port_name, True)
1914 vsctl_qos = vsctl_port.qos
1915 ctx.del_qos(vsctl_qos)
1917 def _cmd_del_qos(self, ctx, command):
1918 port_name = command.args[0]
1919 self._del_qos(ctx, port_name)
1921 def _set_qos(self, ctx, port_name, type, max_rate):
1922 ctx.populate_cache()
1923 vsctl_port = ctx.find_port(port_name, True)
1924 ovsrec_qos = ctx.set_qos(vsctl_port, type, max_rate)
1927 def _cmd_set_qos(self, ctx, command):
1928 port_name = command.args[0]
1929 type = command.args[1]
1930 max_rate = command.args[2]
1931 result = self._set_qos(ctx, port_name, type, max_rate)
1932 command.result = [result]
1934 def _pre_cmd_set_qos(self, ctx, command):
1935 self._pre_get_info(ctx, command)
1936 schema_helper = self.schema_helper
1937 schema_helper.register_columns(
1938 vswitch_idl.OVSREC_TABLE_QOS,
1939 [vswitch_idl.OVSREC_QOS_COL_EXTERNAL_IDS,
1940 vswitch_idl.OVSREC_QOS_COL_OTHER_CONFIG,
1941 vswitch_idl.OVSREC_QOS_COL_QUEUES,
1942 vswitch_idl.OVSREC_QOS_COL_TYPE])
1944 def _cmd_set_queue(self, ctx, command):
1945 ctx.populate_cache()
1946 port_name = command.args[0]
1947 queues = command.args[1]
1948 vsctl_port = ctx.find_port(port_name, True)
1949 vsctl_qos = vsctl_port.qos
1952 for queue in queues:
1953 max_rate = queue.get('max-rate', None)
1954 min_rate = queue.get('min-rate', None)
1955 ovsrec_queue = ctx.set_queue(
1956 vsctl_qos, max_rate, min_rate, queue_id)
1957 results.append(ovsrec_queue)
1959 command.result = results
1961 def _pre_cmd_set_queue(self, ctx, command):
1962 self._pre_get_info(ctx, command)
1963 schema_helper = self.schema_helper
1964 schema_helper.register_columns(
1965 vswitch_idl.OVSREC_TABLE_QUEUE,
1966 [vswitch_idl.OVSREC_QUEUE_COL_DSCP,
1967 vswitch_idl.OVSREC_QUEUE_COL_EXTERNAL_IDS,
1968 vswitch_idl.OVSREC_QUEUE_COL_OTHER_CONFIG])
1970 # Database commands:
1973 _VSCtlTable(vswitch_idl.OVSREC_TABLE_BRIDGE,
1974 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_BRIDGE,
1975 vswitch_idl.OVSREC_BRIDGE_COL_NAME,
1977 _VSCtlTable(vswitch_idl.OVSREC_TABLE_CONTROLLER,
1978 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_BRIDGE,
1979 vswitch_idl.OVSREC_BRIDGE_COL_NAME,
1980 vswitch_idl.OVSREC_BRIDGE_COL_CONTROLLER)]),
1981 _VSCtlTable(vswitch_idl.OVSREC_TABLE_INTERFACE,
1982 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_INTERFACE,
1983 vswitch_idl.OVSREC_INTERFACE_COL_NAME,
1985 _VSCtlTable(vswitch_idl.OVSREC_TABLE_MIRROR,
1986 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_MIRROR,
1987 vswitch_idl.OVSREC_MIRROR_COL_NAME,
1989 _VSCtlTable(vswitch_idl.OVSREC_TABLE_MANAGER,
1990 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_MANAGER,
1991 vswitch_idl.OVSREC_MANAGER_COL_TARGET,
1993 _VSCtlTable(vswitch_idl.OVSREC_TABLE_NETFLOW,
1994 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_BRIDGE,
1995 vswitch_idl.OVSREC_BRIDGE_COL_NAME,
1996 vswitch_idl.OVSREC_BRIDGE_COL_NETFLOW)]),
1997 _VSCtlTable(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH,
1998 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH,
2001 _VSCtlTable(vswitch_idl.OVSREC_TABLE_PORT,
2002 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_PORT,
2003 vswitch_idl.OVSREC_PORT_COL_NAME,
2005 _VSCtlTable(vswitch_idl.OVSREC_TABLE_QOS,
2006 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_PORT,
2007 vswitch_idl.OVSREC_PORT_COL_NAME,
2008 vswitch_idl.OVSREC_PORT_COL_QOS)]),
2009 _VSCtlTable(vswitch_idl.OVSREC_TABLE_QUEUE,
2010 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_QOS,
2012 vswitch_idl.OVSREC_QOS_COL_QUEUES)]),
2013 _VSCtlTable(vswitch_idl.OVSREC_TABLE_SSL,
2014 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_OPEN_VSWITCH,
2016 vswitch_idl.OVSREC_OPEN_VSWITCH_COL_SSL)]),
2017 _VSCtlTable(vswitch_idl.OVSREC_TABLE_SFLOW,
2018 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_BRIDGE,
2019 vswitch_idl.OVSREC_BRIDGE_COL_NAME,
2020 vswitch_idl.OVSREC_BRIDGE_COL_SFLOW)]),
2021 _VSCtlTable(vswitch_idl.OVSREC_TABLE_FLOW_TABLE,
2022 [_VSCtlRowID(vswitch_idl.OVSREC_TABLE_FLOW_TABLE,
2023 vswitch_idl.OVSREC_FLOW_TABLE_COL_NAME,
2028 def _score_partial_match(name, s):
2029 _MAX_SCORE = 0xffffffff
2030 assert len(name) < _MAX_SCORE
2031 s = s[:_MAX_SCORE - 1] # in practice, this doesn't matter
2035 name = name.lower().replace('-', '_')
2036 s = s.lower().replace('-', '_')
2037 if s.startswith(name):
2038 return _MAX_SCORE - 1
2039 if name.startswith(s):
2045 def _get_table(table_name):
2048 for table in VSCtl._TABLES:
2049 score = VSCtl._score_partial_match(table.table_name, table_name)
2050 if score > best_score:
2053 elif score == best_score:
2059 vsctl_fatal('multiple table names match "%s"' % table_name)
2061 vsctl_fatal('unknown table "%s"' % table_name)
2063 def _pre_get_table(self, _ctx, table_name):
2064 vsctl_table = self._get_table(table_name)
2066 schema_helper = self.schema_helper
2067 schema_helper.register_table(vsctl_table.table_name)
2068 for row_id in vsctl_table.row_ids:
2070 schema_helper.register_table(row_id.table)
2071 if row_id.name_column:
2072 schema_helper.register_columns(row_id.table,
2073 [row_id.name_column])
2074 if row_id.uuid_column:
2075 schema_helper.register_columns(row_id.table,
2076 [row_id.uuid_column])
2079 def _get_column(self, table_name, column_name):
2083 columns = self.schema.tables[table_name].columns.keys()
2084 for column in columns:
2085 score = VSCtl._score_partial_match(column, column_name)
2086 if score > best_score:
2089 elif score == best_score:
2093 # ovs.db.schema_helper._keep_table_columns() requires that
2094 # column_name is type of str. Not unicode string
2095 return str(best_match)
2097 vsctl_fatal('%s contains more than one column whose name '
2098 'matches "%s"' % (table_name, column_name))
2100 vsctl_fatal('%s does not contain a column whose name matches '
2101 '"%s"' % (table_name, column_name))
2103 def _pre_get_column(self, _ctx, table_name, column):
2104 column_name = self._get_column(table_name, column)
2105 self.schema_helper.register_columns(table_name, [column_name])
2107 def _pre_get_columns(self, ctx, table_name, columns):
2108 self._pre_get_table(ctx, table_name)
2109 for column in columns:
2110 self._pre_get_column(ctx, table_name, column)
2112 def _pre_cmd_list(self, ctx, command):
2113 table_name = command.args[0]
2114 self._pre_get_table(ctx, table_name)
2116 def _list(self, ctx, table_name, record_id=None):
2118 for ovsrec_row in ctx.idl.tables[table_name].rows.values():
2119 if record_id is not None and ovsrec_row.name != record_id:
2121 result.append(ovsrec_row)
2125 def _cmd_list(self, ctx, command):
2126 table_name = command.args[0]
2128 if len(command.args) > 1:
2129 record_id = command.args[1]
2131 command.result = self._list(ctx, table_name, record_id)
2133 def _pre_cmd_find(self, ctx, command):
2134 table_name = command.args[0]
2135 table_schema = self.schema.tables[table_name]
2137 ctx.parse_column_key_value(table_schema, column_key_value)[0]
2138 for column_key_value in command.args[1:]]
2140 self._pre_get_columns(ctx, table_name, columns)
2142 def _check_value(self, ovsrec_row, column_value):
2144 :type column_value: tuple of column and value_json
2146 column, value_json = column_value
2147 column_schema = ovsrec_row._table.columns[column]
2148 value = ovs.db.data.Datum.from_json(
2149 column_schema.type, value_json).to_python(ovs.db.idl._uuid_to_row)
2150 datum = getattr(ovsrec_row, column)
2151 if column_schema.type.is_map():
2152 for k, v in value.items():
2153 if k in datum and datum[k] == v:
2155 elif datum == value:
2160 def _find(self, ctx, table_name, column_values):
2162 :type column_values: list of (column, value_json)
2165 for ovsrec_row in ctx.idl.tables[table_name].rows.values():
2166 LOG.debug('ovsrec_row %s', ovsrec_row_to_string(ovsrec_row))
2167 if all(self._check_value(ovsrec_row, column_value)
2168 for column_value in column_values):
2169 result.append(ovsrec_row)
2173 def _cmd_find(self, ctx, command):
2174 table_name = command.args[0]
2175 table_schema = self.schema.tables[table_name]
2177 ctx.parse_column_key_value(table_schema, column_key_value)
2178 for column_key_value in command.args[1:]]
2179 command.result = self._find(ctx, table_name, column_values)
2181 def _pre_cmd_get(self, ctx, command):
2182 table_name = command.args[0]
2184 ctx.parse_column_key(column_key)[0]
2185 for column_key in command.args[2:]]
2187 self._pre_get_columns(ctx, table_name, columns)
2189 def _get(self, ctx, table_name, record_id, column_keys,
2190 id_=None, if_exists=False):
2191 vsctl_table = self._get_table(table_name)
2192 ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
2194 # TODO: Support symbol name
2196 # symbol, new = ctx.create_symbol(id_)
2198 # vsctl_fatal('row id "%s" specified on "get" command was '
2199 # 'used before it was defined' % id_)
2200 # symbol.uuid = row.uuid
2201 # symbol.strong_ref = True
2204 for column, key in column_keys:
2205 result.append(ctx.get_column(ovsrec_row, column, key, if_exists))
2209 def _cmd_get(self, ctx, command):
2210 id_ = None # TODO: Support --id option
2211 if_exists = command.has_option('--if-exists')
2212 table_name = command.args[0]
2213 record_id = command.args[1]
2216 ctx.parse_column_key(column_key)
2217 for column_key in command.args[2:]]
2219 command.result = self._get(
2220 ctx, table_name, record_id, column_keys, id_, if_exists)
2222 def _check_mutable(self, table_name, column):
2223 column_schema = self.schema.tables[table_name].columns[column]
2224 if not column_schema.mutable:
2225 vsctl_fatal('cannot modify read-only column %s in table %s' %
2226 (column, table_name))
2228 def _pre_mod_columns(self, ctx, table_name, columns):
2229 self._pre_get_table(ctx, table_name)
2230 for column in columns:
2231 self._pre_get_column(ctx, table_name, column)
2232 self._check_mutable(table_name, column)
2234 def _pre_cmd_set(self, ctx, command):
2235 table_name = command.args[0]
2236 table_schema = self.schema.tables[table_name]
2238 ctx.parse_column_key_value(table_schema, column_key_value)[0]
2239 for column_key_value in command.args[2:]]
2241 self._pre_mod_columns(ctx, table_name, columns)
2243 def _set(self, ctx, table_name, record_id, column_values):
2245 :type column_values: list of (column, value_json)
2247 vsctl_table = self._get_table(table_name)
2248 ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
2249 for column, value in column_values:
2250 ctx.set_column(ovsrec_row, column, value)
2251 ctx.invalidate_cache()
2253 def _cmd_set(self, ctx, command):
2254 table_name = command.args[0]
2255 record_id = command.args[1]
2257 # column_key_value: <column>[:<key>]=<value>
2258 table_schema = self.schema.tables[table_name]
2260 ctx.parse_column_key_value(table_schema, column_key_value)
2261 for column_key_value in command.args[2:]]
2263 self._set(ctx, table_name, record_id, column_values)
2265 def _pre_cmd_add(self, ctx, command):
2266 table_name = command.args[0]
2267 columns = [command.args[2]]
2269 self._pre_mod_columns(ctx, table_name, columns)
2271 def _add(self, ctx, table_name, record_id, column_values):
2273 :type column_values: list of (column, value_json)
2275 vsctl_table = self._get_table(table_name)
2276 ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
2277 for column, value in column_values:
2278 ctx.add_column(ovsrec_row, column, value)
2279 ctx.invalidate_cache()
2281 def _cmd_add(self, ctx, command):
2282 table_name = command.args[0]
2283 record_id = command.args[1]
2284 column = command.args[2]
2286 column_key_value_strings = []
2287 for value in command.args[3:]:
2289 # construct <column>:<key>=value
2290 column_key_value_strings.append('%s:%s' % (column, value))
2292 # construct <column>=value
2293 column_key_value_strings.append('%s=%s' % (column, value))
2295 table_schema = self.schema.tables[table_name]
2297 ctx.parse_column_key_value(table_schema, column_key_value_string)
2298 for column_key_value_string in column_key_value_strings]
2300 self._add(ctx, table_name, record_id, column_values)
2302 def _pre_cmd_remove(self, ctx, command):
2303 table_name = command.args[0]
2304 columns = [command.args[2]]
2306 self._pre_mod_columns(ctx, table_name, columns)
2308 def _remove(self, ctx, table_name, record_id, column_values):
2310 :type column_values: list of (column, value_json)
2312 vsctl_table = self._get_table(table_name)
2313 ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
2314 for column, value in column_values:
2315 ctx.remove_column(ovsrec_row, column, value)
2316 ctx.invalidate_cache()
2318 def _cmd_remove(self, ctx, command):
2319 table_name = command.args[0]
2320 record_id = command.args[1]
2321 column = command.args[2]
2323 column_key_value_strings = []
2324 for value in command.args[3:]:
2326 # construct <column>:<key>=value
2327 column_key_value_strings.append('%s:%s' % (column, value))
2329 # construct <column>=value
2330 column_key_value_strings.append('%s=%s' % (column, value))
2332 table_schema = self.schema.tables[table_name]
2334 ctx.parse_column_key_value(table_schema, column_key_value_string)
2335 for column_key_value_string in column_key_value_strings]
2337 self._remove(ctx, table_name, record_id, column_values)
2339 def _pre_cmd_clear(self, ctx, command):
2340 table_name = command.args[0]
2341 column = command.args[2]
2342 self._pre_mod_columns(ctx, table_name, [column])
2344 def _clear(self, ctx, table_name, record_id, column):
2345 vsctl_table = self._get_table(table_name)
2346 ovsrec_row = ctx.must_get_row(vsctl_table, record_id)
2347 column_schema = ctx.idl.tables[table_name].columns[column]
2348 if column_schema.type.n_min > 0:
2349 vsctl_fatal('"clear" operation cannot be applied to column %s '
2350 'of table %s, which is not allowed to be empty' %
2351 (column, table_name))
2353 # assuming that default datum is empty.
2354 default_datum = ovs.db.data.Datum.default(column_schema.type)
2355 setattr(ovsrec_row, column,
2356 default_datum.to_python(ovs.db.idl._uuid_to_row))
2357 ctx.invalidate_cache()
2359 def _cmd_clear(self, ctx, command):
2360 table_name = command.args[0]
2361 record_id = command.args[1]
2362 column = command.args[2]
2363 self._clear(ctx, table_name, record_id, column)
2367 # Create constants from ovs db schema
2370 def schema_print(schema_location, prefix):
2371 prefix = prefix.upper()
2373 json = ovs.json.from_file(schema_location)
2374 schema = ovs.db.schema.DbSchema.from_json(json)
2376 print('# Do NOT edit.')
2377 print('# This is automatically generated by %s' % __file__)
2378 print('# created based on version %s' % (schema.version or 'unknown'))
2381 print('%s_DB_NAME = \'%s\'' % (prefix, schema.name))
2382 for table in sorted(schema.tables.values(),
2383 key=operator.attrgetter('name')):
2385 print('%s_TABLE_%s = \'%s\'' % (prefix,
2386 table.name.upper(), table.name))
2387 for column in sorted(table.columns.values(),
2388 key=operator.attrgetter('name')):
2389 print('%s_%s_COL_%s = \'%s\'' % (prefix, table.name.upper(),
2390 column.name.upper(),
2395 if len(sys.argv) <= 2:
2396 print('Usage: %s <schema file>' % sys.argv[0])
2397 print('e.g.: %s vswitchd/vswitch.ovsschema' % sys.argv[0])
2399 location = sys.argv[1]
2401 schema_print(location, prefix)
2404 if __name__ == '__main__':