Hi On Tue, Jan 21, 2025 at 10:47 PM Roman Penyaev <r.peni...@gmail.com> wrote: > > Mux is a character backend (host side) device, which multiplexes > multiple frontends with one backend device. The following is a > few lines from the QEMU manpage [1]: > > A multiplexer is a "1:N" device, and here the "1" end is your > specified chardev backend, and the "N" end is the various parts > of QEMU that can talk to a chardev. > > But sadly multiple backends are not supported. > > This work implements a new chardev backend `hub` device, which > aggregates input from multiple backend devices and forwards it to a > single frontend device. Additionally, `hub` device takes the output > from the frontend device and sends it back to all the connected > backend devices. This allows for seamless interaction between > different backend devices and a single frontend interface. > > The motivation is the EVE project [2], where it would be very > convenient to have a virtio console frontend device on the guest that > can be controlled from multiple backend devices, namely VNC and local > TTY emulator. The following is an example of the QEMU command line: > > -chardev pty,path=/tmp/pty,id=pty0 \ > -chardev vc,id=vc0 \ > -chardev hub,id=hub0,chardevs.0=pty0,chardevs.1=vc0 \ > -device virtconsole,chardev=hub0 \ > -vnc 0.0.0.0:0 > > Which creates two backend devices: > > * Text virtual console (`vc0`) > * A pseudo TTY (`pty0`) connected to the single virtio hvc console with the > help of a new backend aggregator (`hub0`) > > `vc0` renders text to an image, which can be shared over the VNC > protocol. `pty0` is a pseudo TTY backend which provides bidirectional > communication to the virtio hvc console. > > Once QEMU starts, the VNC client and any TTY emulator can be used to > control a single hvc console. For example, these two different > consoles should have similar input and output due to the buffer > aggregation: > > # Start TTY emulator > tio /tmp/pty > > # Start VNC client and switch to virtual console Ctrl-Alt-2 > vncviewer :0 > > 'chardevs.N' list syntax is used for the sake of compatibility with > the representation of JSON lists in 'key=val' pairs format of the > util/keyval.c, despite the fact that modern QAPI way of parsing, > namely qobject_input_visitor_new_str(), is not used. Choice of keeping > QAPI list syntax may help to smoothly switch to modern parsing in the > future. > > v7 .. v8: > > * No need for a separate `->frontend` pointer in the hub device > structure, use `hub->parent.fe` directly. > * Remove special handling of !EAGAIN error while serving write > to all backends. This should be safe, because detached backends > are handled by the `->be_open` flag check. > * Combine `hub_chr_write_to_all()` and `hub_chr_write()` calls. > * Fix docs generation: no single backtick, but double, so not > a `hub` but ``hub`` in qemu-options.hx > > v6 .. v7: > > After discussing v6 it was decided to: > > * Rename "multiplexer" to "aggregator" > * Rename "mux-be" device type to "hub" > * Drop all changes related to the original multiplexer implementation > > Code changes: > > * Added counting of CHR_EVENT_OPENED and CHR_EVENT_CLOSED events > coming from backend devices. This prevents frontend devices from > closing if one of the backend devices has been disconnected. The > logic is simple: "the last one turns off the light". > > v5 .. v6: > > * Rebased on latest master > * Changed how chardev is attached to a multiplexer: with version 6 > mux should specify list elements with ID of chardevs: > > chardevs.0=ID[,chardevs.N=ID] > > 'chardevs.N' list syntax is used for the sake of compatibility with > the representation of JSON lists in 'key=val' pairs format of the > util/keyval.c, despite the fact that modern QAPI way of parsing, > namely qobject_input_visitor_new_str(), is not used. Choice of keeping > QAPI list syntax may help to smoothly switch to modern parsing in the > future. > > v4 .. v5: > > * Spelling fixes in qemu-options description > * Memory leaks fixes in mux-be tests > * Add sanity checks to chardev to avoid stacking of mux devices > * Add corresponding unit test case to cover the creation of stacked > muxers: `-chardev mux-be,mux-id-be=ID`, which is forbidden > * Reflect the fact that stacking is not supported in the documentation > > v3 .. v4: > > * Rebase on latest chardev changes > * Add unit tests which test corner cases: > * Inability to remove mux with active frontend > * Inability to add more chardevs to a mux than `MUX_MAX` > * Inability to mix mux-fe and mux-be for the same chardev > > v2 .. v3: > > * Split frontend and backend multiplexer implementations and > move them to separate files: char-mux-fe.c and char-mux-be.c > > v1 .. v2: > > * Separate type for the backend multiplexer `mux-be` > * Handle EAGAIN on write to the backend device > * Support of watch of previously failed backend device > * Proper json support of the `mux-be-id` option > * Unit test for the `mux-be` multiplexer > > [1] https://www.qemu.org/docs/master/system/qemu-manpage.html#hxtool-6 > [2] https://github.com/lf-edge/eve > > Signed-off-by: Roman Penyaev <r.peni...@gmail.com> > Cc: "Marc-André Lureau" <marcandre.lur...@redhat.com> > Cc: Markus Armbruster <arm...@redhat.com> > Cc: Kevin Wolf <kw...@redhat.com> > Cc: Daniel P. Berrange <berra...@redhat.com> > Cc: qemu-devel@nongnu.org
Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> > > Roman Penyaev (4): > chardev/char-pty: send CHR_EVENT_CLOSED on disconnect > chardev/char-hub: implement backend chardev aggregator > tests/unit/test-char: add unit tests for hub chardev backend > qemu-options.hx: describe hub chardev and aggregation of several > backends > > chardev/char-hub.c | 301 ++++++++++++++++++++++++++++ > chardev/char-pty.c | 4 +- > chardev/char.c | 23 ++- > chardev/chardev-internal.h | 51 ++++- > chardev/meson.build | 1 + > include/chardev/char.h | 1 + > qapi/char.json | 27 +++ > qemu-options.hx | 48 ++++- > tests/unit/test-char.c | 398 +++++++++++++++++++++++++++++++++++++ > 9 files changed, 846 insertions(+), 8 deletions(-) > create mode 100644 chardev/char-hub.c > > -- > 2.43.0 >