QEMU internal APIs How abstractions inside QEMU (don't) work - - PowerPoint PPT Presentation

qemu internal apis
SMART_READER_LITE
LIVE PREVIEW

QEMU internal APIs How abstractions inside QEMU (don't) work - - PowerPoint PPT Presentation

QEMU internal APIs How abstractions inside QEMU (don't) work together Eduardo Habkost <ehabkost@redhat.com> 1 Contents Context: QEMU features and interfaces Overview of some internal QEMU APIs Interaction between different abstractions


slide-1
SLIDE 1

QEMU internal APIs

How abstractions inside QEMU (don't) work together

Eduardo Habkost <ehabkost@redhat.com>

1

slide-2
SLIDE 2

Contents

Context: QEMU features and interfaces Overview of some internal QEMU APIs Interaction between different abstractions

2 . 1

slide-3
SLIDE 3

Not included:

The right way to do something Solutions to issues Every single API in QEMU

2 . 2

slide-4
SLIDE 4

Context

3 . 1

slide-5
SLIDE 5

"QEMU is a generic and open source machine emulator and virtualizer." — http://qemu.org/

3 . 2

slide-6
SLIDE 6

External Interfaces

3 . 3

slide-7
SLIDE 7

Command-line

$ qemu-system-x86_64 -cpu Nehalem -vga cirrus \

  • device e1000,mac=01:02:03:04:05:06 \
  • machine pc-i440fx-2.7,accel=kvm

3 . 4

slide-8
SLIDE 8

Config files

[device] driver = "e1000" mac = "01:02:03:04:05:06" [machine] type = "pc-i440fx-2.7" accel = "kvm"

3 . 5

slide-9
SLIDE 9

Human Monitor (HMP)

QEMU 2.8.50 monitor - type 'help' for more information (qemu) device_add e1000,mac=01:02:03:04:05:06 (qemu) info network e1000.0: index=0,type=nic,model=e1000,macaddr=01:02:03:04:05:06 (qemu) info kvm kvm support: enabled (qemu) info cpus * CPU #0: pc=0xffffffff8105ea06 (halted) thread_id=21209 (qemu)

3 . 6

slide-10
SLIDE 10

Machine Monitor (QMP)

⇒ { "execute": "device_add", "arguments": { "mac": "01:02:03:04:05:06", "driver": "e1000" } } ⇐ { "return": {} } ⇒ { "execute": "query-cpus", "arguments": {} } ⇐ { "return": [{ "halted": false, "pc": 133130950, "current": true, "qom_path": "/machine/unattached/device[0]", "thread_id": 22230, "arch": "x86", "CPU": 0 } ] } ⇒ { "execute": "query-kvm", "arguments": {} } ⇐ { "return": { "enabled": true, "present": true } }

3 . 7

slide-11
SLIDE 11

QEMU Internals

4 . 1

slide-12
SLIDE 12

Things to handle:

Configuration options Monitor commands Device configuration Device state (including migration) Backend configuration etc.

4 . 2

slide-13
SLIDE 13

Internal APIs

4 . 3

slide-14
SLIDE 14

API: QemuOpts (2009)

Handling of command-line and config file options Few basic data types Flat data model

4 . 4

slide-15
SLIDE 15

QemuOpts usage

Most Many command-line options Internal storage of config options Config file support (-readconfig, -writeconfig)

4 . 5

slide-16
SLIDE 16

QemuOpts example

$ qemu-system-x86_64 -memory 2G,maxmem=4G static QemuOptsList qemu_mem_opts = { .name = "memory", .implied_opt_name = "size", .head = QTAILQ_HEAD_INITIALIZER(qemu_mem_opts.head), .merge_lists = true, .desc = { { .name = "size", .type = QEMU_OPT_SIZE, }, { .name = "slots", .type = QEMU_OPT_NUMBER, }, { .name = "maxmem", .type = QEMU_OPT_SIZE, }, { /* end of list */ } }, };

4 . 6

slide-17
SLIDE 17

API: qdev (2009)

Bus/device tree Single API to create, configure and plug devices Property system, introspection Rebuilt on top of QOM (2011)

4 . 7

slide-18
SLIDE 18

qdev usage

Every device emulated by QEMU External generic interfaces (e.g. -device, device_add) Introspection of device tree (e.g. info qtree)

4 . 8

slide-19
SLIDE 19

qdev Example

$ qemu-system-x86_64 -device e1000,mac=12:34:56:78:9a:bc #define DEFINE_NIC_PROPERTIES(_state, _conf) \ DEFINE_PROP_MACADDR("mac", _state, _conf.macaddr), \ DEFINE_PROP_VLAN("vlan", _state, _conf.peers), \ DEFINE_PROP_NETDEV("netdev", _state, _conf.peers) static Property e1000_properties[] = { DEFINE_NIC_PROPERTIES(E1000State, conf), DEFINE_PROP_BIT("autonegotiation", E1000State, compat_flags, E1000_FLAG_AUTONEG_BIT, true), /* [...] */ };

4 . 9

slide-20
SLIDE 20

qdev device tree

(qemu) info qtree bus: main-system-bus type System dev: hpet, id "" gpio-in "" 2 gpio-out "" 1 gpio-out "sysbus-irq" 32 timers = 3 (0x3) msi = false hpet-intcap = 4 (0x4) mmio 00000000fed00000/0000000000000400 dev: kvm-ioapic, id "" gpio-in "" 24 gsi_base = 0 (0x0) mmio 00000000fec00000/0000000000001000 dev: i440FX-pcihost, id ""

4 . 10

slide-21
SLIDE 21

API: QAPI (2011)

Formal schema for interfaces Visitor API Generated code for: C types Serialization Visitors QMP commands and events Interface introspection Documentation

4 . 11

slide-22
SLIDE 22

QAPI usage

All QMP commands Some command-line options

4 . 12

slide-23
SLIDE 23

QAPI Example: chardev-add

⇒ { "execute" : "chardev-add", "arguments" : { "id" : "bar", "backend" : { "type" : "file", "data" : { "out" : "/tmp/bar.log" } } } } ⇐ { "return": {} }

4 . 13

slide-24
SLIDE 24

chardev-add QAPI schema

{ 'command': 'chardev-add', 'data': { 'id': 'str', 'backend': 'ChardevBackend' }, 'returns': 'ChardevReturn' } { 'union': 'ChardevBackend', 'data': { 'file': 'ChardevFile', 'serial': 'ChardevHostdev', [...] } } { 'struct': 'ChardevFile', 'data': { '*in' : 'str', 'out' : 'str', '*append': 'bool' }, 'base': 'ChardevCommon' } ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp);

4 . 14

slide-25
SLIDE 25

API: QOM (2011)

(Don't confuse with QObject)

QEMU Object Model Type hierarchy Property system, introspection qdev rebuilt on top of it

4 . 15

slide-26
SLIDE 26

QOM in action

$ qemu-system-x86_64 -device e1000,mac=12:34:56:78:9a:bc $ qemu-system-x86_64 \

  • object memory-backend-file,size=512M,mem-path=/hugetlbfs \

[...] $ qemu-system-x86_64 -machine pc,accel=kvm $ qemu-system-x86_64 -cpu Nehalem,+vmx,-nx,pmu=on qemu_irq qemu_allocate_irq(...) { irq = IRQ(object_new(TYPE_IRQ)); [...] } void memory_region_init(...) {

  • bject_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);

[...] }

4 . 16

slide-27
SLIDE 27

Mixing Abstractions

5 . 1

slide-28
SLIDE 28

Example: -numa option

(QemuOpts + QAPI)

$ qemu-system-x86_64 -numa node,cpus=0-1,mem=2G \

  • numa node,2-3,mem=2G

5 . 2

slide-29
SLIDE 29
  • numa QemuOptsList

QemuOptsList qemu_numa_opts = { .name = "numa", .implied_opt_name = "type", .head = QTAILQ_HEAD_INITIALIZER(qemu_numa_opts.head), .desc = { { 0 } } };

5 . 3

slide-30
SLIDE 30
  • numa QAPI schema

{ 'union': 'NumaOptions', 'data': { 'node': 'NumaNodeOptions' } } { 'struct': 'NumaNodeOptions', 'data': { '*nodeid': 'uint16', '*cpus': ['uint16'], '*mem': 'size', '*memdev': 'str' } }

5 . 4

slide-31
SLIDE 31
  • numa glue

static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) { NumaOptions *object = NULL; Visitor *v = opts_visitor_new(opts); visit_type_NumaOptions(v, NULL, &object, &err); /* [...] */ }

5 . 5

slide-32
SLIDE 32

Summary: -numa

QAPI-based implementation QemuOpts-based interface All options documented in QAPI schema No duplication of QAPI schema info in the C code Glue code made possible by OptsVisitor Similar method used for:

  • net, -netdev, -acpitable, -machine

5 . 6

slide-33
SLIDE 33

Example object-add QMP command

(QAPI + QOM)

⇒ { "execute": "object-add", "arguments": { "qom-type": "rng-random", "id": "rng1", "props": { "filename": "/dev/hwrng" } } } ⇐ { "return": {} }

5 . 7

slide-34
SLIDE 34
  • bject-add: QOM properties

static void rng_random_init(Object *obj) { RngRandom *s = RNG_RANDOM(obj);

  • bject_property_add_str(obj, "filename",

rng_random_get_filename, rng_random_set_filename, NULL); /* [...] */ }

5 . 8

slide-35
SLIDE 35
  • bject-add QAPI schema

{ 'command': 'object-add', 'data': {'qom-type': 'str', 'id': 'str', '*props': 'any' } }

5 . 9

slide-36
SLIDE 36

Summary: object-add

QOM-based implementation QAPI-based interface QAPI schema is incomplete Similar method used for: device_add

5 . 10

slide-37
SLIDE 37

Example: -cpu option

(command-line + qdev/QOM)

$ qemu-system-x86_64 -cpu Nehalem,+vmx,-nx,pmu=on

5 . 11

slide-38
SLIDE 38
  • cpu: QOM properties

void x86_cpu_register_bit_prop(X86CPU *cpu, const char *prop_name, uint32_t *field, int bitnr) {

  • bject_property_add(OBJECT(cpu), prop_name, "bool",

x86_cpu_get_bit_prop, x86_cpu_set_bit_prop, x86_cpu_release_bit_prop, fp, &error_abort); } /* [...] */ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), /* [...] */ };

5 . 12

slide-39
SLIDE 39
  • cpu: glue code

static void x86_cpu_parse_featurestr(const char *typename, char *features, Error **errp) { for (featurestr = strtok(features, ","); featurestr; featurestr = strtok(NULL, ",")) { /* [...] */ prop->driver = typename; prop->property = g_strdup(name); prop->value = g_strdup(val); prop->errp = &error_fatal; qdev_prop_register_global(prop); } }

5 . 13

slide-40
SLIDE 40

Summary: -cpu

qdev/QOM-based implementation command-line interface Glue based on qdev's -global properties Not described on QAPI schema Still not ported to QemuOpts

5 . 14

slide-41
SLIDE 41

Example: query-cpu-model-expansion

(QAPI + QOM)

⇒ { "execute": "query-cpu-model-expansion", "arguments": { "type": "static", "model": { "name": "Nehalem" } } } ⇐ {"return": { "model": {"name": "base", "props": { "cmov": true, "ia64": false, "aes": false, "mmx": true, "rdpid": false, "arat": false, [...] } } } }

5 . 15

slide-42
SLIDE 42

q-c-m-expansion: QAPI schema

{ 'command': 'query-cpu-model-expansion', 'data': { 'type': 'CpuModelExpansionType', 'model': 'CpuModelInfo' }, 'returns': 'CpuModelExpansionInfo' } { 'struct': 'CpuModelExpansionInfo', 'data': { 'model': 'CpuModelInfo' } } { 'struct': 'CpuModelInfo', 'data': { 'name': 'str', '*props': 'any' } }

5 . 16

slide-43
SLIDE 43

Summary: q-c-m-expansion

qdev/QOM-based implementation QAPI-based interface QAPI schema is incomplete Arch-specific glue code (currently)

5 . 17

slide-44
SLIDE 44

Summary: QOM & the QAPI schema

QOM classes and properties are registered at run time (class_init & instance_init methods) QAPI schema is a static file QOM class-specific info doesn't appear on QAPI schema

5 . 18

slide-45
SLIDE 45

Conclusion

5 . 19

slide-46
SLIDE 46

Please ask

Some practices are not well-documented. When in doubt, ask developers & qemu-devel.

5 . 20

slide-47
SLIDE 47

Questions?

5 . 21

slide-48
SLIDE 48

Thank You

This slide deck: Incomplete guide to QEMU APIs: https://habkost.net/talks/fosdem-2017/ https://goo.gl/c8SzD7

5 . 22

slide-49
SLIDE 49

Appendix

5 . 23

slide-50
SLIDE 50

Interface documentation

QAPI schema: comprehensive QemuOpts: brief QOM types and properties: almost none

5 . 24

slide-51
SLIDE 51

Data types

Type int float bool string enum list dict QemuOpts ✔* ✔ ✔ ✔** qdev ✔* ✔ ✔ ✔ QAPI ✔ ✔ ✔ ✔ ✔ ✔ ✔ QOM ✔ ✔ ✔ ✔ ✔ ✔** ✔**

* Limited support ** Very limited support

5 . 25

slide-52
SLIDE 52

Abstractions equivalency

QemuOpts qdev QOM QObject QAPI QemuOptsList type class

  • schema

struct QemuOptDesc property property

  • schema

field

  • ption default

property default property default

  • QemuOpts

device instance QDict C struct QemuOpt property value property value QObject C field

static data runtime data

5 . 26

slide-53
SLIDE 53

QOM: internal vs. external

Unclear: What should be user-visible What should be a stable interface Types can be hidden from the user (no_user) Properties can't be hidden Today's (undocumented) convention: "x-" prefix

5 . 27

slide-54
SLIDE 54

QOM tree manipulation

QOM device/object tree can be manipulated through QMP Not very popular in practice

5 . 28

slide-55
SLIDE 55

Not Covered

Migration system (VMState, savevm handlers) Main loop Char devices Block layer Coroutines Many more

5 . 29

slide-56
SLIDE 56

Interfaces vs internal abstractions

QMP commands: built on top of QAPI (Many) Command-line options: handled using QemuOpts

  • device/device_add: built on top of qdev
  • object/object-add: built on top of QOM
  • cpu: built on top of qdev

5 . 30

slide-57
SLIDE 57

Can translate:

QAPI ⇔ QObject qdev ⇒ QOM (qdev is QOM) QemuOpts ⇒ QAPI structs QemuOpts ⇒ QOM

5 . 31

slide-58
SLIDE 58

anything ⇒ QAPI schema

Not possible by definition (QAPI schema is a static source code file)

5 . 32

slide-59
SLIDE 59

anything ⇒ QemuOpts

Not translated Limited QemuOpts data model Not a problem in practice

5 . 33

slide-60
SLIDE 60

Other "schema" data

(QAPI schema, QOM type hierarchy, config groups) No mechanisms for translation QOM/QAPI dilemma when designing new interfaces Normally we choose QAPI Exceptions: CPU config, device_add and object- add options Exception: a few QemuOpts config groups (property descriptions are optional)

5 . 34

slide-61
SLIDE 61

Issue: Introspection & data availability

5 . 35

slide-62
SLIDE 62

Translation issues:

Incompatible data-types Data unavailable at the right time

5 . 36

slide-63
SLIDE 63

Issue: overlap and duplication

APIs providing similar features Some code is not shared

5 . 37

slide-64
SLIDE 64

Duplication example:

Parsing code

5 . 38

slide-65
SLIDE 65

Overlap example:

Data representation: QemuOpts vs QOM vs QAPI OK when translation is possible Interface design dilemmas when translation is not possible Affects design of external interfaces

5 . 39

slide-66
SLIDE 66

Steps

Compile time (static) Runtime: Event: Initialization (static) static var hardcoded at main() QOM/qdev type registration QOM/qdev class_init QOM/qdev instantiation Event: Monitor is available Event: machine creation Event: machine is running

5 . 40

slide-67
SLIDE 67

Data items

qdev type list QOM properties QemuOpts sections QAPI schema machine-type list machine-type defaults machine-type devices

5 . 41

slide-68
SLIDE 68

Static data treated like dynamic data

QOM type hierarchy QOM property lists machine-type default options machine-type default devices/buses

5 . 42

slide-69
SLIDE 69

Dynamic data whose static defaults are hard to discover

machine-type default options machine-type default devices/buses

5 . 43

slide-70
SLIDE 70

Static data that never becomes available to the outside

Some machine-type behavior

5 . 44