qemu/tests/qtest/libqos/qgraph.h
<<
>>
Prefs
   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
  29typedef struct QOSGraphObject QOSGraphObject;
  30typedef struct QOSGraphNode QOSGraphNode;
  31typedef struct QOSGraphEdge QOSGraphEdge;
  32typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions;
  33typedef struct QOSGraphTestOptions QOSGraphTestOptions;
  34
  35/* Constructor for drivers, machines and test */
  36typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc,
  37                                      void *addr);
  38typedef void *(*QOSCreateMachineFunc) (QTestState *qts);
  39typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc);
  40
  41/* QOSGraphObject functions */
  42typedef void *(*QOSGetDriver) (void *object, const char *interface);
  43typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name);
  44typedef void (*QOSDestructorFunc) (QOSGraphObject *object);
  45typedef void (*QOSStartFunct) (QOSGraphObject *object);
  46
  47/* Test options functions */
  48typedef 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 */
  73struct 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 */
  96struct 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 */
 134struct 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 */
 146void qos_graph_init(void);
 147
 148/**
 149 * qos_graph_destroy(): deallocates all the hash tables,
 150 * freeing all nodes and edges.
 151 */
 152void 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 */
 159void 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 */
 166void 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 */
 183void 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 */
 196void 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 */
 206void 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 */
 219void 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 */
 234void 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 */
 273void 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 */
 285void 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 */
 299void 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 */
 307void 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 */
 314const 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 */
 327void *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 */
 333void 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 */
 340void 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 */
 346void 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 */
 355QOSGraphObject *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 */
 366QOSGraphObject *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 */
 388void qos_dump_graph(void);
 389
 390#endif
 391