qapi: introduce new cmd option "allow-oob"
Here "oob" stands for "Out-Of-Band". When "allow-oob" is set, it means the command allows out-of-band execution. The "oob" idea is proposed by Markus Armbruster in following thread: https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg02057.html This new "allow-oob" boolean will be exposed by "query-qmp-schema" as well for command entries, so that QMP clients can know which commands can be used in out-of-band calls. For example the command "migrate" originally looks like: {"name": "migrate", "ret-type": "17", "meta-type": "command", "arg-type": "86"} And it'll be changed into: {"name": "migrate", "ret-type": "17", "allow-oob": false, "meta-type": "command", "arg-type": "86"} This patch only provides the QMP interface level changes. It does not contain the real out-of-band execution implementation yet. Suggested-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Signed-off-by: Peter Xu <peterx@redhat.com> Message-Id: <20180309090006.10018-18-peterx@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [eblake: rebase on introspection done by qlit] Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
		
							parent
							
								
									bf1e730174
								
							
						
					
					
						commit
						876c67512e
					
				| @ -20,8 +20,9 @@ typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); | ||||
| 
 | ||||
| typedef enum QmpCommandOptions | ||||
| { | ||||
|     QCO_NO_OPTIONS = 0x0, | ||||
|     QCO_NO_SUCCESS_RESP = 0x1, | ||||
|     QCO_NO_OPTIONS            =  0x0, | ||||
|     QCO_NO_SUCCESS_RESP       =  (1U << 0), | ||||
|     QCO_ALLOW_OOB             =  (1U << 1), | ||||
| } QmpCommandOptions; | ||||
| 
 | ||||
| typedef struct QmpCommand | ||||
|  | ||||
| @ -259,12 +259,16 @@ | ||||
| # | ||||
| # @ret-type: the name of the command's result type. | ||||
| # | ||||
| # @allow-oob: whether the command allows out-of-band execution. | ||||
| #             (Since: 2.12) | ||||
| # | ||||
| # TODO: @success-response (currently irrelevant, because it's QGA, not QMP) | ||||
| # | ||||
| # Since: 2.5 | ||||
| ## | ||||
| { 'struct': 'SchemaInfoCommand', | ||||
|   'data': { 'arg-type': 'str', 'ret-type': 'str' } } | ||||
|   'data': { 'arg-type': 'str', 'ret-type': 'str', | ||||
|             'allow-oob': 'bool' } } | ||||
| 
 | ||||
| ## | ||||
| # @SchemaInfoEvent: | ||||
|  | ||||
| @ -193,10 +193,18 @@ out: | ||||
|     return ret | ||||
| 
 | ||||
| 
 | ||||
| def gen_register_command(name, success_response): | ||||
|     options = 'QCO_NO_OPTIONS' | ||||
| def gen_register_command(name, success_response, allow_oob): | ||||
|     options = [] | ||||
| 
 | ||||
|     if not success_response: | ||||
|         options = 'QCO_NO_SUCCESS_RESP' | ||||
|         options += ['QCO_NO_SUCCESS_RESP'] | ||||
|     if allow_oob: | ||||
|         options += ['QCO_ALLOW_OOB'] | ||||
| 
 | ||||
|     if not options: | ||||
|         options = ['QCO_NO_OPTIONS'] | ||||
| 
 | ||||
|     options = " | ".join(options) | ||||
| 
 | ||||
|     ret = mcgen(''' | ||||
|     qmp_register_command(cmds, "%(name)s", | ||||
| @ -268,7 +276,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); | ||||
|         genc.add(gen_registry(self._regy, self._prefix)) | ||||
| 
 | ||||
|     def visit_command(self, name, info, arg_type, ret_type, | ||||
|                       gen, success_response, boxed): | ||||
|                       gen, success_response, boxed, allow_oob): | ||||
|         if not gen: | ||||
|             return | ||||
|         self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) | ||||
| @ -277,7 +285,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); | ||||
|             self._genc.add(gen_marshal_output(ret_type)) | ||||
|         self._genh.add(gen_marshal_decl(name)) | ||||
|         self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) | ||||
|         self._regy += gen_register_command(name, success_response) | ||||
|         self._regy += gen_register_command(name, success_response, allow_oob) | ||||
| 
 | ||||
| 
 | ||||
| def gen_commands(schema, output_dir, prefix): | ||||
|  | ||||
| @ -921,7 +921,8 @@ def check_exprs(exprs): | ||||
|         elif 'command' in expr: | ||||
|             meta = 'command' | ||||
|             check_keys(expr_elem, 'command', [], | ||||
|                        ['data', 'returns', 'gen', 'success-response', 'boxed']) | ||||
|                        ['data', 'returns', 'gen', 'success-response', | ||||
|                         'boxed', 'allow-oob']) | ||||
|         elif 'event' in expr: | ||||
|             meta = 'event' | ||||
|             check_keys(expr_elem, 'event', [], ['data', 'boxed']) | ||||
| @ -1044,7 +1045,7 @@ class QAPISchemaVisitor(object): | ||||
|         pass | ||||
| 
 | ||||
|     def visit_command(self, name, info, arg_type, ret_type, | ||||
|                       gen, success_response, boxed): | ||||
|                       gen, success_response, boxed, allow_oob): | ||||
|         pass | ||||
| 
 | ||||
|     def visit_event(self, name, info, arg_type, boxed): | ||||
| @ -1421,7 +1422,7 @@ class QAPISchemaAlternateType(QAPISchemaType): | ||||
| 
 | ||||
| class QAPISchemaCommand(QAPISchemaEntity): | ||||
|     def __init__(self, name, info, doc, arg_type, ret_type, | ||||
|                  gen, success_response, boxed): | ||||
|                  gen, success_response, boxed, allow_oob): | ||||
|         QAPISchemaEntity.__init__(self, name, info, doc) | ||||
|         assert not arg_type or isinstance(arg_type, str) | ||||
|         assert not ret_type or isinstance(ret_type, str) | ||||
| @ -1432,6 +1433,7 @@ class QAPISchemaCommand(QAPISchemaEntity): | ||||
|         self.gen = gen | ||||
|         self.success_response = success_response | ||||
|         self.boxed = boxed | ||||
|         self.allow_oob = allow_oob | ||||
| 
 | ||||
|     def check(self, schema): | ||||
|         if self._arg_type_name: | ||||
| @ -1455,7 +1457,8 @@ class QAPISchemaCommand(QAPISchemaEntity): | ||||
|     def visit(self, visitor): | ||||
|         visitor.visit_command(self.name, self.info, | ||||
|                               self.arg_type, self.ret_type, | ||||
|                               self.gen, self.success_response, self.boxed) | ||||
|                               self.gen, self.success_response, | ||||
|                               self.boxed, self.allow_oob) | ||||
| 
 | ||||
| 
 | ||||
| class QAPISchemaEvent(QAPISchemaEntity): | ||||
| @ -1674,6 +1677,7 @@ class QAPISchema(object): | ||||
|         gen = expr.get('gen', True) | ||||
|         success_response = expr.get('success-response', True) | ||||
|         boxed = expr.get('boxed', False) | ||||
|         allow_oob = expr.get('allow-oob', False) | ||||
|         if isinstance(data, OrderedDict): | ||||
|             data = self._make_implicit_object_type( | ||||
|                 name, info, doc, 'arg', self._make_members(data, info)) | ||||
| @ -1681,7 +1685,8 @@ class QAPISchema(object): | ||||
|             assert len(rets) == 1 | ||||
|             rets = self._make_array_type(rets[0], info) | ||||
|         self._def_entity(QAPISchemaCommand(name, info, doc, data, rets, | ||||
|                                            gen, success_response, boxed)) | ||||
|                                            gen, success_response, | ||||
|                                            boxed, allow_oob)) | ||||
| 
 | ||||
|     def _def_event(self, expr, info, doc): | ||||
|         name = expr['event'] | ||||
|  | ||||
| @ -227,7 +227,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): | ||||
|                                body=texi_entity(doc, 'Members'))) | ||||
| 
 | ||||
|     def visit_command(self, name, info, arg_type, ret_type, | ||||
|                       gen, success_response, boxed): | ||||
|                       gen, success_response, boxed, allow_oob): | ||||
|         doc = self.cur_doc | ||||
|         if boxed: | ||||
|             body = texi_body(doc) | ||||
|  | ||||
| @ -41,6 +41,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False): | ||||
|         ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n' | ||||
|         ret += ',\n'.join(elts) + '\n' | ||||
|         ret += indent(level) + '}))' | ||||
|     elif isinstance(obj, bool): | ||||
|         ret += 'QLIT_QBOOL(%s)' % ('true' if obj else 'false') | ||||
|     else: | ||||
|         assert False                # not implemented | ||||
|     return ret | ||||
| @ -170,12 +172,13 @@ const QLitObject %(c_name)s = %(c_string)s; | ||||
|                                     for m in variants.variants]}) | ||||
| 
 | ||||
|     def visit_command(self, name, info, arg_type, ret_type, | ||||
|                       gen, success_response, boxed): | ||||
|                       gen, success_response, boxed, allow_oob): | ||||
|         arg_type = arg_type or self._schema.the_empty_object_type | ||||
|         ret_type = ret_type or self._schema.the_empty_object_type | ||||
|         self._gen_qlit(name, 'command', | ||||
|                        {'arg-type': self._use_type(arg_type), | ||||
|                         'ret-type': self._use_type(ret_type)}) | ||||
|                         'ret-type': self._use_type(ret_type), | ||||
|                         'allow-oob': allow_oob}) | ||||
| 
 | ||||
|     def visit_event(self, name, info, arg_type, boxed): | ||||
|         arg_type = arg_type or self._schema.the_empty_object_type | ||||
|  | ||||
| @ -42,7 +42,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): | ||||
|         self._print_variants(variants) | ||||
| 
 | ||||
|     def visit_command(self, name, info, arg_type, ret_type, | ||||
|                       gen, success_response, boxed): | ||||
|                       gen, success_response, boxed, allow_oob): | ||||
|         print('command %s %s -> %s' % \ | ||||
|               (name, arg_type and arg_type.name, ret_type and ret_type.name)) | ||||
|         print('   gen=%s success_response=%s boxed=%s' % \ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Peter Xu
						Peter Xu