[PATCH v8 0/4] chardev: implement backend chardev multiplexing

Roman Penyaev posted 4 patches 1 day, 5 hours ago
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
[PATCH v8 0/4] chardev: implement backend chardev multiplexing
Posted by Roman Penyaev 1 day, 5 hours ago
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.peniaev@gmail.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Daniel P. Berrange <berrange@redhat.com>
Cc: qemu-devel@nongnu.org

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


Re: [PATCH v8 0/4] chardev: implement backend chardev multiplexing
Posted by Marc-André Lureau 16 hours ago
Hi

On Tue, Jan 21, 2025 at 10:47 PM Roman Penyaev <r.peniaev@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.peniaev@gmail.com>
> Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Kevin Wolf <kwolf@redhat.com>
> Cc: Daniel P. Berrange <berrange@redhat.com>
> Cc: qemu-devel@nongnu.org

Reviewed-by: Marc-André Lureau <marcandre.lureau@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
>