]> git.proxmox.com Git - mirror_qemu.git/blame - tests/libqos/qgraph.h
Clean up includes
[mirror_qemu.git] / tests / libqos / qgraph.h
CommitLineData
fc281c80
EGE
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 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
fc281c80 22#include <gmodule.h>
fc281c80
EGE
23#include "qemu/module.h"
24#include "malloc.h"
25
26/* maximum path length */
27#define QOS_PATH_MAX_ELEMENT_SIZE 50
28
29typedef struct QOSGraphObject QOSGraphObject;
30typedef struct QOSGraphNode QOSGraphNode;
31typedef struct QOSGraphEdge QOSGraphEdge;
32typedef struct QOSGraphNodeOptions QOSGraphNodeOptions;
33typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions;
34typedef struct QOSGraphTestOptions QOSGraphTestOptions;
35
36/* Constructor for drivers, machines and test */
37typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc,
38 void *addr);
39typedef void *(*QOSCreateMachineFunc) (QTestState *qts);
40typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc);
41
42/* QOSGraphObject functions */
43typedef void *(*QOSGetDriver) (void *object, const char *interface);
44typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name);
45typedef void (*QOSDestructorFunc) (QOSGraphObject *object);
46typedef void (*QOSStartFunct) (QOSGraphObject *object);
47
48/* Test options functions */
49typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg);
50
51/**
52 * SECTION: qgraph.h
53 * @title: Qtest Driver Framework
54 * @short_description: interfaces to organize drivers and tests
55 * as nodes in a graph
56 *
57 * This Qgraph API provides all basic functions to create a graph
58 * and instantiate nodes representing machines, drivers and tests
59 * representing their relations with CONSUMES, PRODUCES, and CONTAINS
60 * edges.
61 *
62 * The idea is to have a framework where each test asks for a specific
63 * driver, and the framework takes care of allocating the proper devices
64 * required and passing the correct command line arguments to QEMU.
65 *
66 * A node can be of four types:
67 * - QNODE_MACHINE: for example "arm/raspi2"
68 * - QNODE_DRIVER: for example "generic-sdhci"
69 * - QNODE_INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
70 * an interface is not explicitly created, it will be auto-
71 * matically instantiated when a node consumes or produces
72 * it.
73 * - QNODE_TEST: for example "sdhci-test", consumes an interface and tests
74 * the functions provided
75 *
76 * Notes for the nodes:
77 * - QNODE_MACHINE: each machine struct must have a QGuestAllocator and
78 * implement get_driver to return the allocator passing
79 * "memory". The function can also return NULL if the
80 * allocator is not set.
81 * - QNODE_DRIVER: driver names must be unique, and machines and nodes
82 * planned to be "consumed" by other nodes must match QEMU
83 * drivers name, otherwise they won't be discovered
84 *
85 * An edge relation between two nodes (drivers or machines) X and Y can be:
86 * - X CONSUMES Y: Y can be plugged into X
87 * - X PRODUCES Y: X provides the interface Y
88 * - X CONTAINS Y: Y is part of X component
89 *
90 * Basic framework steps are the following:
91 * - All nodes and edges are created in their respective
92 * machine/driver/test files
93 * - The framework starts QEMU and asks for a list of available devices
94 * and machines (note that only machines and "consumed" nodes are mapped
95 * 1:1 with QEMU devices)
96 * - The framework walks the graph starting from the available machines and
97 * performs a Depth First Search for tests
98 * - Once a test is found, the path is walked again and all drivers are
99 * allocated accordingly and the final interface is passed to the test
100 * - The test is executed
101 * - Unused objects are cleaned and the path discovery is continued
102 *
103 * Depending on the QEMU binary used, only some drivers/machines will be
104 * available and only test that are reached by them will be executed.
105 *
106 * <example>
107 * <title>Creating new driver an its interface</title>
108 * <programlisting>
109 #include "libqos/qgraph.h"
110
111 struct My_driver {
112 QOSGraphObject obj;
113 Node_produced prod;
114 Node_contained cont;
115 }
116
117 static void my_destructor(QOSGraphObject *obj)
118 {
119 g_free(obj);
120 }
121
122 static void my_get_driver(void *object, const char *interface) {
123 My_driver *dev = object;
124 if (!g_strcmp0(interface, "my_interface")) {
125 return &dev->prod;
126 }
127 abort();
128 }
129
130 static void my_get_device(void *object, const char *device) {
131 My_driver *dev = object;
132 if (!g_strcmp0(device, "my_driver_contained")) {
133 return &dev->cont;
134 }
135 abort();
136 }
137
138 static void *my_driver_constructor(void *node_consumed,
139 QOSGraphObject *alloc)
140 {
141 My_driver dev = g_new(My_driver, 1);
142 // get the node pointed by the produce edge
143 dev->obj.get_driver = my_get_driver;
144 // get the node pointed by the contains
145 dev->obj.get_device = my_get_device;
146 // free the object
147 dev->obj.destructor = my_destructor;
148 do_something_with_node_consumed(node_consumed);
149 // set all fields of contained device
150 init_contained_device(&dev->cont);
151 return &dev->obj;
152 }
153
154 static void register_my_driver(void)
155 {
156 qos_node_create_driver("my_driver", my_driver_constructor);
157 // contained drivers don't need a constructor,
158 // they will be init by the parent.
159 qos_node_create_driver("my_driver_contained", NULL);
160
161 // For the sake of this example, assume machine x86_64/pc contains
162 // "other_node".
163 // This relation, along with the machine and "other_node" creation,
164 // should be defined in the x86_64_pc-machine.c file.
165 // "my_driver" will then consume "other_node"
166 qos_node_contains("my_driver", "my_driver_contained");
167 qos_node_produces("my_driver", "my_interface");
168 qos_node_consumes("my_driver", "other_node");
169 }
170 * </programlisting>
171 * </example>
172 *
173 * In the above example, all possible types of relations are created:
174 * node "my_driver" consumes, contains and produces other nodes.
175 * more specifically:
176 * x86_64/pc -->contains--> other_node <--consumes-- my_driver
177 * |
178 * my_driver_contained <--contains--+
179 * |
180 * my_interface <--produces--+
181 *
182 * or inverting the consumes edge in consumed_by:
183 *
184 * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
185 * |
186 * my_driver_contained <--contains--+
187 * |
188 * my_interface <--produces--+
189 *
190 * <example>
191 * <title>Creating new test</title>
192 * <programlisting>
193 * #include "libqos/qgraph.h"
194 *
195 * static void my_test_function(void *obj, void *data)
196 * {
197 * Node_produced *interface_to_test = obj;
198 * // test interface_to_test
199 * }
200 *
201 * static void register_my_test(void)
202 * {
203 * qos_add_test("my_interface", "my_test", my_test_function);
204 * }
205 *
206 * libqos_init(register_my_test);
207 *
208 * </programlisting>
209 * </example>
210 *
211 * Here a new test is created, consuming "my_interface" node
212 * and creating a valid path from a machine to a test.
213 * Final graph will be like this:
214 * x86_64/pc -->contains--> other_node <--consumes-- my_driver
215 * |
216 * my_driver_contained <--contains--+
217 * |
218 * my_test --consumes--> my_interface <--produces--+
219 *
220 * or inverting the consumes edge in consumed_by:
221 *
222 * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
223 * |
224 * my_driver_contained <--contains--+
225 * |
226 * my_test <--consumed_by-- my_interface <--produces--+
227 *
228 * Assuming there the binary is
229 * QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64
230 * a valid test path will be:
231 * "/x86_64/pc/other_node/my_driver/my_interface/my_test".
232 *
233 * Additional examples are also in libqos/test-qgraph.c
234 *
235 * Command line:
236 * Command line is built by using node names and optional arguments
237 * passed by the user when building the edges.
238 *
239 * There are three types of command line arguments:
240 * - in node : created from the node name. For example, machines will
241 * have "-M <machine>" to its command line, while devices
242 * "-device <device>". It is automatically done by the
243 * framework.
244 * - after node : added as additional argument to the node name.
245 * This argument is added optionally when creating edges,
246 * by setting the parameter @after_cmd_line and
247 * @extra_edge_opts in #QOSGraphEdgeOptions.
248 * The framework automatically adds
249 * a comma before @extra_edge_opts,
250 * because it is going to add attributes
251 * after the destination node pointed by
252 * the edge containing these options, and automatically
253 * adds a space before @after_cmd_line, because it
254 * adds an additional device, not an attribute.
255 * - before node : added as additional argument to the node name.
256 * This argument is added optionally when creating edges,
257 * by setting the parameter @before_cmd_line in
258 * #QOSGraphEdgeOptions. This attribute
259 * is going to add attributes before the destination node
260 * pointed by the edge containing these options. It is
261 * helpful to commands that are not node-representable,
262 * such as "-fdsev" or "-netdev".
263 *
264 * While adding command line in edges is always used, not all nodes names are
265 * used in every path walk: this is because the contained or produced ones
266 * are already added by QEMU, so only nodes that "consumes" will be used to
267 * build the command line. Also, nodes that will have { "abstract" : true }
268 * as QMP attribute will loose their command line, since they are not proper
269 * devices to be added in QEMU.
270 *
271 * Example:
272 *
273 QOSGraphEdgeOptions opts = {
274 .arg = NULL,
275 .size_arg = 0,
276 .after_cmd_line = "-device other",
277 .before_cmd_line = "-netdev something",
278 .extra_edge_opts = "addr=04.0",
279 };
280 QOSGraphNode * node = qos_node_create_driver("my_node", constructor);
281 qos_node_consumes_args("my_node", "interface", &opts);
282 *
283 * Will produce the following command line:
284 * "-netdev something -device my_node,addr=04.0 -device other"
285 */
286
287/**
288 * Edge options to be passed to the contains/consumes *_args function.
289 */
290struct QOSGraphEdgeOptions {
291 void *arg; /*
292 * optional arg that will be used by
293 * dest edge
294 */
295 uint32_t size_arg; /*
296 * optional arg size that will be used by
297 * dest edge
298 */
299 const char *extra_device_opts;/*
300 *optional additional command line for dest
301 * edge, used to add additional attributes
302 * *after* the node command line, the
303 * framework automatically prepends ","
304 * to this argument.
305 */
306 const char *before_cmd_line; /*
307 * optional additional command line for dest
308 * edge, used to add additional attributes
309 * *before* the node command line, usually
310 * other non-node represented commands,
311 * like "-fdsev synt"
312 */
313 const char *after_cmd_line; /*
314 * optional extra command line to be added
315 * after the device command. This option
316 * is used to add other devices
317 * command line that depend on current node.
318 * Automatically prepends " " to this
319 * argument
320 */
321 const char *edge_name; /*
322 * optional edge to differentiate multiple
323 * devices with same node name
324 */
325};
326
327/**
328 * Test options to be passed to the test functions.
329 */
330struct QOSGraphTestOptions {
331 QOSGraphEdgeOptions edge; /* edge arguments that will be used by test.
332 * Note that test *does not* use edge_name,
333 * and uses instead arg and size_arg as
334 * data arg for its test function.
335 */
336 void *arg; /* passed to the .before function, or to the
337 * test function if there is no .before
338 * function
339 */
340 QOSBeforeTest before; /* executed before the test. Can add
341 * additional parameters to the command line
342 * and modify the argument to the test function.
343 */
344 bool subprocess; /* run the test in a subprocess */
345};
346
347/**
348 * Each driver, test or machine of this framework will have a
349 * QOSGraphObject as first field.
350 *
351 * This set of functions offered by QOSGraphObject are executed
352 * in different stages of the framework:
353 * - get_driver / get_device : Once a machine-to-test path has been
354 * found, the framework traverses it again and allocates all the
355 * nodes, using the provided constructor. To satisfy their relations,
356 * i.e. for produces or contains, where a struct constructor needs
357 * an external parameter represented by the previous node,
358 * the framework will call get_device (for contains) or
359 * get_driver (for produces), depending on the edge type, passing
360 * them the name of the next node to be taken and getting from them
361 * the corresponding pointer to the actual structure of the next node to
362 * be used in the path.
363 *
364 * - start_hw: This function is executed after all the path objects
365 * have been allocated, but before the test is run. It starts the hw, setting
366 * the initial configurations (*_device_enable) and making it ready for the
367 * test.
368 *
369 * - destructor: Opposite to the node constructor, destroys the object.
370 * This function is called after the test has been executed, and performs
371 * a complete cleanup of each node allocated field. In case no constructor
372 * is provided, no destructor will be called.
373 *
374 */
375struct QOSGraphObject {
376 /* for produces edges, returns void * */
377 QOSGetDriver get_driver;
378 /* for contains edges, returns a QOSGraphObject * */
379 QOSGetDevice get_device;
380 /* start the hw, get ready for the test */
381 QOSStartFunct start_hw;
382 /* destroy this QOSGraphObject */
383 QOSDestructorFunc destructor;
384 /* free the memory associated to the QOSGraphObject and its contained
385 * children */
386 GDestroyNotify free;
387};
388
389/**
390 * qos_graph_init(): initialize the framework, creates two hash
391 * tables: one for the nodes and another for the edges.
392 */
393void qos_graph_init(void);
394
395/**
396 * qos_graph_destroy(): deallocates all the hash tables,
397 * freeing all nodes and edges.
398 */
399void qos_graph_destroy(void);
400
401/**
402 * qos_node_destroy(): removes and frees a node from the,
403 * nodes hash table.
404 */
405void qos_node_destroy(void *key);
406
407/**
408 * qos_edge_destroy(): removes and frees an edge from the,
409 * edges hash table.
410 */
411void qos_edge_destroy(void *key);
412
413/**
414 * qos_add_test(): adds a test node @name to the nodes hash table.
415 *
416 * The test will consume a @interface node, and once the
417 * graph walking algorithm has found it, the @test_func will be
418 * executed. It also has the possibility to
419 * add an optional @opts (see %QOSGraphNodeOptions).
420 *
421 * For tests, opts->edge.arg and size_arg represent the arg to pass
422 * to @test_func
423 */
424void qos_add_test(const char *name, const char *interface,
425 QOSTestFunc test_func,
426 QOSGraphTestOptions *opts);
427
428/**
429 * qos_node_create_machine(): creates the machine @name and
430 * adds it to the node hash table.
431 *
432 * This node will be of type QNODE_MACHINE and have @function
433 * as constructor
434 */
435void qos_node_create_machine(const char *name, QOSCreateMachineFunc function);
436
437/**
438 * qos_node_create_machine_args(): same as qos_node_create_machine,
439 * but with the possibility to add an optional ", @opts" after -M machine
440 * command line.
441 */
442void qos_node_create_machine_args(const char *name,
443 QOSCreateMachineFunc function,
444 const char *opts);
445
446/**
447 * qos_node_create_driver(): creates the driver @name and
448 * adds it to the node hash table.
449 *
450 * This node will be of type QNODE_DRIVER and have @function
451 * as constructor
452 */
453void qos_node_create_driver(const char *name, QOSCreateDriverFunc function);
454
455/**
456 * qos_node_contains(): creates an edge of type QEDGE_CONTAINS and
457 * adds it to the edge list mapped to @container in the
458 * edge hash table.
459 *
460 * This edge will have @container as source and @contained as destination.
461 *
462 * It also has the possibility to add optional NULL-terminated
463 * @opts parameters (see %QOSGraphEdgeOptions)
464 *
465 * This function can be useful when there are multiple devices
466 * with the same node name contained in a machine/other node
467 *
468 * For example, if "arm/raspi2" contains 2 "generic-sdhci"
469 * devices, the right commands will be:
470 * qos_node_create_machine("arm/raspi2");
471 * qos_node_create_driver("generic-sdhci", constructor);
472 * //assume rest of the fields are set NULL
473 * QOSGraphEdgeOptions op1 = { .edge_name = "emmc" };
474 * QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" };
475 * qos_node_contains("arm/raspi2", "generic-sdhci", &op1, &op2, NULL);
476 *
477 * Of course this also requires that the @container's get_device function
478 * should implement a case for "emmc" and "sdcard".
479 *
480 * For contains, op1.arg and op1.size_arg represent the arg to pass
481 * to @contained constructor to properly initialize it.
482 */
483void qos_node_contains(const char *container, const char *contained, ...);
484
485/**
486 * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and
487 * adds it to the edge list mapped to @producer in the
488 * edge hash table.
489 *
490 * This edge will have @producer as source and @interface as destination.
491 */
492void qos_node_produces(const char *producer, const char *interface);
493
494/**
495 * qos_node_consumes(): creates an edge of type QEDGE_CONSUMED_BY and
496 * adds it to the edge list mapped to @interface in the
497 * edge hash table.
498 *
499 * This edge will have @interface as source and @consumer as destination.
500 * It also has the possibility to add an optional @opts
501 * (see %QOSGraphEdgeOptions)
502 */
503void qos_node_consumes(const char *consumer, const char *interface,
504 QOSGraphEdgeOptions *opts);
505
506/**
507 * qos_invalidate_command_line(): invalidates current command line, so that
508 * qgraph framework cannot try to cache the current command line and
509 * forces QEMU to restart.
510 */
511void qos_invalidate_command_line(void);
512
513/**
514 * qos_get_current_command_line(): return the command line required by the
515 * machine and driver objects. This is the same string that was passed to
516 * the test's "before" callback, if any.
517 */
518const char *qos_get_current_command_line(void);
519
520/**
521 * qos_allocate_objects():
522 * @qts: The #QTestState that will be referred to by the machine object.
523 * @alloc: Where to store the allocator for the machine object, or %NULL.
524 *
525 * Allocate driver objects for the current test
526 * path, but relative to the QTestState @qts.
527 *
528 * Returns a test object just like the one that was passed to
529 * the test function, but relative to @qts.
530 */
531void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc);
532
533/**
534 * qos_object_destroy(): calls the destructor for @obj
535 */
536void qos_object_destroy(QOSGraphObject *obj);
537
538/**
539 * qos_object_queue_destroy(): queue the destructor for @obj so that it is
540 * called at the end of the test
541 */
542void qos_object_queue_destroy(QOSGraphObject *obj);
543
544/**
545 * qos_object_start_hw(): calls the start_hw function for @obj
546 */
547void qos_object_start_hw(QOSGraphObject *obj);
548
549/**
550 * qos_machine_new(): instantiate a new machine node
551 * @node: A machine node to be instantiated
552 * @qts: The #QTestState that will be referred to by the machine object.
553 *
554 * Returns a machine object.
555 */
556QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
557
558/**
559 * qos_machine_new(): instantiate a new driver node
560 * @node: A driver node to be instantiated
561 * @parent: A #QOSGraphObject to be consumed by the new driver node
562 * @alloc: An allocator to be used by the new driver node.
563 * @arg: The argument for the consumed-by edge to @node.
564 *
565 * Calls the constructor for the driver object.
566 */
567QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
568 QGuestAllocator *alloc, void *arg);
569
570
571#endif