feat(itf): add dual-QEMU ivshmem integration-test environment#617
feat(itf): add dual-QEMU ivshmem integration-test environment#617Rahul-Sutariya wants to merge 2 commits into
Conversation
f56837b to
eedfda4
Compare
5bd6beb to
38c934b
Compare
castler
left a comment
There was a problem hiding this comment.
Let's first align on the test infrastructure - then we can check out the example :)
| def dual_qemu_integration_test( | ||
| name, | ||
| srcs, | ||
| filesystem, |
There was a problem hiding this comment.
Do we not need two filesystems here?
There was a problem hiding this comment.
We can have multiple binaries in one filesystem Ex.
pkg_application(
name = "gateway_test_apps",
app_name = "gateway_test",
bin = [":app1", ":app2"], # both binaries in one package
)
If we want separate, then i can extend the macro to accept two filesystem targets and build two IFS images
There was a problem hiding this comment.
Yes - I think we should have two filesystems to be more variable (e.g. imagine having different IP configurations one day or different boot ups or what ever)
There was a problem hiding this comment.
Adapted the changes for second filesystem, THanks
| # Driving two real QNX guests under KVM has rare, environment-induced boot | ||
| # nondeterminism (e.g. a guest occasionally wedging during device bring-up). | ||
| # The fixtures already stagger boots and wait for stable SSH; mark the test | ||
| # flaky so bazel transparently retries such infrastructure hiccups. |
There was a problem hiding this comment.
Ouch - is this possible to be fixed? Should we add a ticket with a todo?
There was a problem hiding this comment.
It's a KVM + QNX -kernel boot path timing issue — the second guest occasionally wedges during SMP AP startup when both initialize under the same KVM instance. The plugin already mitigates by booting VMs sequentially and using single-core guests, which makes it very rare but not fully eliminable from our side.
A proper fix would require either:
- QNX fixing the boot-path race in their -kernel loader (upstream QNX issue), or
- Using the -bios/UEFI boot path instead of -kernel (different QNX IFS packaging, not trivial).
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class IvshmemQemu: |
There was a problem hiding this comment.
We now copied here a lot from: https://github.com/eclipse-score/itf/blob/main/score/itf/plugins/qemu/qemu.py can we not use some software mechanisms to reduce code duplication? Inheritance? Decorators?
There was a problem hiding this comment.
The Qemu class uses double-underscore name mangling (__build_qemu_command, __find_available_kvm_support, etc.), which Python mangles to _Qemu__build_qemu_command — making inheritance/override impossible from a subclass. There's no extra_args hook or any other extension point to inject additional -object/-device flags.
There was a problem hiding this comment.
we can rename __build_qemu_command to _build_qemu_command (drop the name mangling) and add an overridable _extra_qemu_args() hook that the base command assembly calls. (itf repo changes) then we can avoid duplication, want me creat pr for ITF repo?
| def __exit__(self, exc_type, exc_val, exc_tb): | ||
| self.stop() | ||
|
|
||
| def start(self, subprocess_params=None): |
There was a problem hiding this comment.
should this not only start one instance? and then when we have another instance of this class, we will start the otherone?
There was a problem hiding this comment.
Yes, that's exactly how it works. Each IvshmemQemu instance starts one QEMU process. In the plugin's _targets fixture, the loop creates a separate instance per VM
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class DualQemuProcess: |
There was a problem hiding this comment.
Should we not inherit from here: https://github.com/eclipse-score/itf/blob/main/score/itf/plugins/qemu/qemu_process.py#L22?
Where is our equivalent to https://github.com/eclipse-score/itf/blob/main/score/itf/plugins/qemu/qemu_target.py ?
There was a problem hiding this comment.
QemuProcess: Can't inherit — it hardcodes Qemu(...) in init with no way to inject a different launcher. If upstream accepted the Qemu instance as a constructor parameter (DI), DualQemuProcess could be eliminated entirely.
QemuTarget: We already reuse it directly (from score.itf.plugins.qemu.qemu_target import QemuTarget). No custom equivalent needed — DualQemuProcess exposes the same .stop()/.restart()/.console interface that QemuTarget expects.
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def _wait_for_ssh(target, total_timeout: int = 180, interval: int = 3, stable_successes: int = 3): |
There was a problem hiding this comment.
These helper functions must be used already somewhere else in the other Qemu plugin, no?
There was a problem hiding this comment.
No — the single-VM plugin only does pre_tests_phase (5 SSH retries with fixed timeouts). It doesn't need stable-success counting or boot-restart logic because a single QNX guest under KVM boots reliably. These helpers address problems specific to the dual-VM scenario (sshd instability during concurrent boots, occasional total boot wedges, and the first VM going quiet while the second initializes). They're new logic rather than duplication from upstream.
6c98422 to
01bea3d
Compare
| makers = [] | ||
| for index, vm in enumerate(dual_config.vms): | ||
| def make_process(index=index, vm=vm): | ||
| return DualQemuProcess( |
There was a problem hiding this comment.
Why are we not using
with DualQemuProcess(...) as target_a:
with DualQemuProcess(...) as target_b:
yield target_a, tarbet_b
This would make things IMHO way more clear, would avoid the complicated loop and would enable to give each QemuProcess also its custom configuration.
There was a problem hiding this comment.
Adapted the changes, Thanks
Add a `dual_qemu` ITF/pytest plugin that boots two QNX VMs sharing one QEMU ivshmem-plain region, extending the upstream single-VM `qemu` plugin. - plugin: config.py, ivshmem_qemu.py, dual_qemu_process.py, __init__.py (target_a/target_b fixtures; sequential boot to avoid KVM race), BUILD, example config, README, example/run_example_manually.sh. - integration_testing.bzl: dual_qemu_integration_test macro (QNX-only, flaky). - example: offset_list.h + simple_ivshmem.cpp map the ivshmem BAR via pci-server and exchange a self-relative offset-pointer list, proving cross-VM pointer resolution; simple_ivshmem_test.py verifies both VMs.
note: Cross-VM shared memory forces the region onto the ivshmem PCI BAR (device/SHMCTL_PHYS memory), but the production lib-memory ControlBlock puts a process-shared pthread_mutex there and locks it during init. QNX refuses to operate a process-shared mutex on device-mapped BAR memory (returns EINVAL even with write-back caching), so the producer aborts — making the umbrella score::memory::shared unusable over ivshmem, unlike the mutex-free demo.
01bea3d to
b783e72
Compare
Add a
dual_qemuITF/pytest plugin that boots two QNX VMs sharing one QEMU ivshmem-plain region, extending the upstream single-VMqemuplugin.