xref: /qemu/tests/qtest/libqos/qgraph.h (revision b355f08a3724d3f29e1c177dde3a01b649108f98)
1  /*
2   * libqos driver framework
3   *
4   * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public
8   * License version 2.1 as published by the Free Software Foundation.
9   *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, see <http://www.gnu.org/licenses/>
17   */
18  
19  #ifndef QGRAPH_H
20  #define QGRAPH_H
21  
22  #include <gmodule.h>
23  #include "qemu/module.h"
24  #include "malloc.h"
25  
26  /* maximum path length */
27  #define QOS_PATH_MAX_ELEMENT_SIZE 50
28  
29  typedef struct QOSGraphObject QOSGraphObject;
30  typedef struct QOSGraphNode QOSGraphNode;
31  typedef struct QOSGraphEdge QOSGraphEdge;
32  typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions;
33  typedef struct QOSGraphTestOptions QOSGraphTestOptions;
34  
35  /* Constructor for drivers, machines and test */
36  typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc,
37                                        void *addr);
38  typedef void *(*QOSCreateMachineFunc) (QTestState *qts);
39  typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc);
40  
41  /* QOSGraphObject functions */
42  typedef void *(*QOSGetDriver) (void *object, const char *interface);
43  typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name);
44  typedef void (*QOSDestructorFunc) (QOSGraphObject *object);
45  typedef void (*QOSStartFunct) (QOSGraphObject *object);
46  
47  /* Test options functions */
48  typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg);
49  
50  /**
51   * struct QOSGraphEdgeOptions:
52   * Edge options to be passed to the contains/consumes \*_args function.
53   * @arg: optional arg that will be used by dest edge
54   * @size_arg: @arg size that will be used by dest edge
55   * @extra_device_opts: optional additional command line for dest
56   *                     edge, used to add additional attributes
57   *                     *after* the node command line, the
58   *                     framework automatically prepends ","
59   *                     to this argument.
60   * @before_cmd_line: optional additional command line for dest
61   *                   edge, used to add additional attributes
62   *                   *before* the node command line, usually
63   *                   other non-node represented commands,
64   *                   like "-fdsev synt"
65   * @after_cmd_line: optional extra command line to be added
66   *                  after the device command. This option
67   *                  is used to add other devices
68   *                  command line that depend on current node.
69   *                  Automatically prepends " " to this argument
70   * @edge_name: optional edge to differentiate multiple
71   *             devices with same node name
72   */
73  struct QOSGraphEdgeOptions {
74      void *arg;
75      uint32_t size_arg;
76      const char *extra_device_opts;
77      const char *before_cmd_line;
78      const char *after_cmd_line;
79      const char *edge_name;
80  };
81  
82  /**
83   * struct QOSGraphTestOptions:
84   * Test options to be passed to the test functions.
85   * @edge: edge arguments that will be used by test.
86   *        Note that test *does not* use edge_name,
87   *        and uses instead arg and size_arg as
88   *        data arg for its test function.
89   * @arg:  if @before is non-NULL, pass @arg there.
90   *        Otherwise pass it to the test function.
91   * @before: executed before the test. Used to add
92   *          additional parameters to the command line
93   *          and modify the argument to the test function.
94   * @subprocess: run the test in a subprocess.
95   */
96  struct QOSGraphTestOptions {
97      QOSGraphEdgeOptions edge;
98      void *arg;
99      QOSBeforeTest before;
100      bool subprocess;
101  };
102  
103  /**
104   * struct QOSGraphObject:
105   * Each driver, test or machine of this framework will have a
106   * QOSGraphObject as first field.
107   *
108   * This set of functions offered by QOSGraphObject are executed
109   * in different stages of the framework:
110   * @get_driver: see @get_device
111   * @get_device: Once a machine-to-test path has been
112   *              found, the framework traverses it again and allocates all the
113   *              nodes, using the provided constructor. To satisfy their
114   *              relations, i.e. for produces or contains, where a struct
115   *              constructor needs an external parameter represented by the
116   *              previous node, the framework will call
117   *              @get_device (for contains) or @get_driver (for produces),
118   *              depending on the edge type, passing them the name of the next
119   *              node to be taken and getting from them the corresponding
120   *              pointer to the actual structure of the next node to
121   *              be used in the path.
122   * @start_hw: This function is executed after all the path objects
123   *            have been allocated, but before the test is run. It starts the
124   *            hw, setting the initial configurations (\*_device_enable) and
125   *            making it ready for the test.
126   * @destructor: Opposite to the node constructor, destroys the object.
127   *              This function is called after the test has been executed, and
128   *              performs a complete cleanup of each node allocated field.
129   *              In case no constructor is provided, no destructor will be
130   *              called.
131   * @free: free the memory associated to the QOSGraphObject and its contained
132   *        children
133   */
134  struct QOSGraphObject {
135      QOSGetDriver get_driver;
136      QOSGetDevice get_device;
137      QOSStartFunct start_hw;
138      QOSDestructorFunc destructor;
139      GDestroyNotify free;
140  };
141  
142  /**
143   * qos_graph_init(): initialize the framework, creates two hash
144   * tables: one for the nodes and another for the edges.
145   */
146  void qos_graph_init(void);
147  
148  /**
149   * qos_graph_destroy(): deallocates all the hash tables,
150   * freeing all nodes and edges.
151   */
152  void qos_graph_destroy(void);
153  
154  /**
155   * qos_node_destroy(): removes and frees a node from the
156   * nodes hash table.
157   * @key: Name of the node
158   */
159  void qos_node_destroy(void *key);
160  
161  /**
162   * qos_edge_destroy(): removes and frees an edge from the
163   * edges hash table.
164   * @key: Name of the node
165   */
166  void qos_edge_destroy(void *key);
167  
168  /**
169   * qos_add_test(): adds a test node @name to the nodes hash table.
170   * @name: Name of the test
171   * @interface: Name of the interface node it consumes
172   * @test_func: Actual test to perform
173   * @opts: Facultative options (see %QOSGraphTestOptions)
174   *
175   * The test will consume a @interface node, and once the
176   * graph walking algorithm has found it, the @test_func will be
177   * executed. It also has the possibility to
178   * add an optional @opts (see %QOSGraphTestOptions).
179   *
180   * For tests, opts->edge.arg and size_arg represent the arg to pass
181   * to @test_func
182   */
183  void qos_add_test(const char *name, const char *interface,
184                    QOSTestFunc test_func,
185                    QOSGraphTestOptions *opts);
186  
187  /**
188   * qos_node_create_machine(): creates the machine @name and
189   * adds it to the node hash table.
190   * @name: Name of the machine
191   * @function: Machine constructor
192   *
193   * This node will be of type QNODE_MACHINE and have @function
194   * as constructor
195   */
196  void qos_node_create_machine(const char *name, QOSCreateMachineFunc function);
197  
198  /**
199   * qos_node_create_machine_args(): same as qos_node_create_machine,
200   * but with the possibility to add an optional ", @opts" after -M machine
201   * command line.
202   * @name: Name of the machine
203   * @function: Machine constructor
204   * @opts: Optional additional command line
205   */
206  void qos_node_create_machine_args(const char *name,
207                                    QOSCreateMachineFunc function,
208                                    const char *opts);
209  
210  /**
211   * qos_node_create_driver(): creates the driver @name and
212   * adds it to the node hash table.
213   * @name: Name of the driver
214   * @function: Driver constructor
215   *
216   * This node will be of type QNODE_DRIVER and have @function
217   * as constructor
218   */
219  void qos_node_create_driver(const char *name, QOSCreateDriverFunc function);
220  
221  /**
222   * qos_node_create_driver_named(): behaves as qos_node_create_driver() with the
223   * extension of allowing to specify a different node name vs. associated QEMU
224   * device name.
225   * @name: Custom, unique name of the node to be created
226   * @qemu_name: Actual (official) QEMU driver name the node shall be
227   * associated with
228   * @function: Driver constructor
229   *
230   * Use this function instead of qos_node_create_driver() if you need to create
231   * several instances of the same QEMU device. You are free to choose a custom
232   * node name, however the chosen node name must always be unique.
233   */
234  void qos_node_create_driver_named(const char *name, const char *qemu_name,
235                                    QOSCreateDriverFunc function);
236  
237  /**
238   * qos_node_contains(): creates one or more edges of type QEDGE_CONTAINS
239   * and adds them to the edge list mapped to @container in the
240   * edge hash table.
241   * @container: Source node that "contains"
242   * @contained: Destination node that "is contained"
243   * @opts: Facultative options (see %QOSGraphEdgeOptions)
244   *
245   * The edges will have @container as source and @contained as destination.
246   *
247   * If @opts is NULL, a single edge will be added with no options.
248   * If @opts is non-NULL, the arguments after @contained represent a
249   * NULL-terminated list of %QOSGraphEdgeOptions structs, and an
250   * edge will be added for each of them.
251   *
252   * This function can be useful when there are multiple devices
253   * with the same node name contained in a machine/other node
254   *
255   * For example, if ``arm/raspi2b`` contains 2 ``generic-sdhci``
256   * devices, the right commands will be:
257   *
258   * .. code::
259   *
260   *    qos_node_create_machine("arm/raspi2b");
261   *    qos_node_create_driver("generic-sdhci", constructor);
262   *    // assume rest of the fields are set NULL
263   *    QOSGraphEdgeOptions op1 = { .edge_name = "emmc" };
264   *    QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" };
265   *    qos_node_contains("arm/raspi2b", "generic-sdhci", &op1, &op2, NULL);
266   *
267   * Of course this also requires that the @container's get_device function
268   * should implement a case for "emmc" and "sdcard".
269   *
270   * For contains, op1.arg and op1.size_arg represent the arg to pass
271   * to @contained constructor to properly initialize it.
272   */
273  void qos_node_contains(const char *container, const char *contained,
274                         QOSGraphEdgeOptions *opts, ...);
275  
276  /**
277   * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and
278   * adds it to the edge list mapped to @producer in the
279   * edge hash table.
280   * @producer: Source node that "produces"
281   * @interface: Interface node that "is produced"
282   *
283   * This edge will have @producer as source and @interface as destination.
284   */
285  void qos_node_produces(const char *producer, const char *interface);
286  
287  /**
288   * qos_node_consumes():  creates an edge of type QEDGE_CONSUMED_BY and
289   * adds it to the edge list mapped to @interface in the
290   * edge hash table.
291   * @consumer: Node that "consumes"
292   * @interface: Interface node that "is consumed by"
293   * @opts: Facultative options (see %QOSGraphEdgeOptions)
294   *
295   * This edge will have @interface as source and @consumer as destination.
296   * It also has the possibility to add an optional @opts
297   * (see %QOSGraphEdgeOptions)
298   */
299  void qos_node_consumes(const char *consumer, const char *interface,
300                         QOSGraphEdgeOptions *opts);
301  
302  /**
303   * qos_invalidate_command_line(): invalidates current command line, so that
304   * qgraph framework cannot try to cache the current command line and
305   * forces QEMU to restart.
306   */
307  void qos_invalidate_command_line(void);
308  
309  /**
310   * qos_get_current_command_line(): return the command line required by the
311   * machine and driver objects.  This is the same string that was passed to
312   * the test's "before" callback, if any.
313   */
314  const char *qos_get_current_command_line(void);
315  
316  /**
317   * qos_allocate_objects():
318   * @qts: The #QTestState that will be referred to by the machine object.
319   * @p_alloc: Where to store the allocator for the machine object, or %NULL.
320   *
321   * Allocate driver objects for the current test
322   * path, but relative to the QTestState @qts.
323   *
324   * Returns a test object just like the one that was passed to
325   * the test function, but relative to @qts.
326   */
327  void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc);
328  
329  /**
330   * qos_object_destroy(): calls the destructor for @obj
331   * @obj: A #QOSGraphObject to destroy
332   */
333  void qos_object_destroy(QOSGraphObject *obj);
334  
335  /**
336   * qos_object_queue_destroy(): queue the destructor for @obj so that it is
337   * called at the end of the test
338   * @obj: A #QOSGraphObject to destroy
339   */
340  void qos_object_queue_destroy(QOSGraphObject *obj);
341  
342  /**
343   * qos_object_start_hw(): calls the start_hw function for @obj
344   * @obj: A #QOSGraphObject containing the start_hw function
345   */
346  void qos_object_start_hw(QOSGraphObject *obj);
347  
348  /**
349   * qos_machine_new(): instantiate a new machine node
350   * @node: Machine node to be instantiated
351   * @qts: A #QTestState that will be referred to by the machine object.
352   *
353   * Returns a machine object.
354   */
355  QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
356  
357  /**
358   * qos_machine_new(): instantiate a new driver node
359   * @node: A driver node to be instantiated
360   * @parent: A #QOSGraphObject to be consumed by the new driver node
361   * @alloc: An allocator to be used by the new driver node.
362   * @arg: The argument for the consumed-by edge to @node.
363   *
364   * Calls the constructor for the driver object.
365   */
366  QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
367                                 QGuestAllocator *alloc, void *arg);
368  
369  /**
370   * qos_dump_graph(): prints all currently existing nodes and
371   * edges to stdout. Just for debugging purposes.
372   *
373   * All qtests add themselves to the overall qos graph by calling qgraph
374   * functions that add device nodes and edges between the individual graph
375   * nodes for tests. As the actual graph is assmbled at runtime by the qos
376   * subsystem, it is sometimes not obvious how the overall graph looks like.
377   * E.g. when writing new tests it may happen that those new tests are simply
378   * ignored by the qtest framework.
379   *
380   * This function allows to identify problems in the created qgraph. Keep in
381   * mind: only tests with a path down from the actual test case node (leaf) up
382   * to the graph's root node are actually executed by the qtest framework. And
383   * the qtest framework uses QMP to automatically check which QEMU drivers are
384   * actually currently available, and accordingly qos marks certain pathes as
385   * 'unavailable' in such cases (e.g. when QEMU was compiled without support for
386   * a certain feature).
387   */
388  void qos_dump_graph(void);
389  
390  #endif
391