pymctp-exerciser-qemu
QEMU I2C and I3C exerciser support for pymctp.
This package provides exerciser implementations for interfacing with QEMU's I2C and I3C virtual devices to send and receive MCTP packets in virtualized environments.
Installation
pip install pymctp-exerciser-qemu
Requirements
- pymctp >= 0.1.0
- crc8 >= 0.1.0
- QEMU with I2C/I3C device support
Exercisers Included
QemuI2CNetDevSocket
Interfaces with QEMU I2C devices via network sockets.
from pymctp.exerciser import get_exerciser
QemuI2CSocket = get_exerciser('qemu-i2c')
socket = QemuI2CSocket(
host='localhost',
port=5555,
addr=0x20
)
QemuI3CCharDevSocket
Interfaces with QEMU I3C devices via character devices.
from pymctp.exerciser import get_exerciser
QemuI3CSocket = get_exerciser('qemu-i3c')
socket = QemuI3CSocket(
chardev_path='/tmp/i3c-socket',
addr=0x20
)
QemuI3CStreamSocket / QemuI2CStreamSocket (TCP "remote target" stream)
Interfaces with QEMU's i3c-target-remote / i2c-target-remote "remote
target" devices over a single, bidirectional TCP connection per endpoint.
This is different from the netdev/netdev2 transports above, which use a
pair of UDP ports (in_port/out_port): the stream transports use one
TCP port per endpoint, with QEMU listening as the TCP server and PyMCTP
connecting as the client. Every message (data, control, and a connect-time
HELLO handshake) is framed the same way on the wire:
[u32 length BE][u8 type][body...]
length counts the bytes of type + body. See
stream_framing.py for the
codec and qemu_i3c_stream.py /
qemu_i2c_stream.py for the
per-transport message types.
Use these through pymctp.automaton.manager.EndpointManager.from_config with
ConfigTypes.I3CStream ("i3c-stream") / ConfigTypes.I2CStream
("i2c-stream"), rather than instantiating the sockets directly:
from pymctp.automaton.manager import ConfigTypes, EndpointManager
# I3CStreamSocketConfig fields: host, port, name, dump_hex=True,
# dump_packet=False, connect_timeout=5.0, pid=0, bcr=0, dcr=0, mwl=0, mrl=0,
# static_addr=0, auto_configure=True (sends SET_REG + HOT_JOIN on connect
# for any non-zero register field).
hcp0_config = {
"context": {
"supported_msg_types": [], # e.g. MsgTypes.CTRL, MsgTypes.PLDM
"assigned_eid": 38,
},
"config": {
"type": ConfigTypes.I3CStream,
"host": "localhost",
"port": 5556,
"name": "HCP0",
},
}
# I2CStreamSocketConfig fields: host, port, name, dump_hex=True,
# dump_packet=False, connect_timeout=5.0, master=False, target_address=None.
hsp1_config = {
"context": {
"physical_address": {"address": 0xB0 >> 1},
"supported_msg_types": [], # e.g. MsgTypes.CTRL, MsgTypes.PLDM
"assigned_eid": 34,
},
"config": {
"type": ConfigTypes.I2CStream,
"host": "localhost",
"port": 5570,
"name": "HSP1",
},
}
hcp0 = EndpointManager.from_config(hcp0_config)
hsp1 = EndpointManager.from_config(hsp1_config)
By default (master=False), the socket speaks the slave/target model
described above: WRITE frames are dispatched as parsed
SmbusTransportPackets, and outbound data is buffered until a READ_REQ
arrives (see qemu_i2c_stream.py).
Setting master=True instead speaks QEMU's i2c-target-remote master
mode (peer-as-master / multi-master, mirroring the old UDP i2c-netdev
transport): QEMU masters the (virtual) I2C bus on our behalf, so there is no
READ_REQ/READ_RSP turn-around — every WRITE frame is address-prefixed
instead:
WRITE (0x00) body := [addr_byte][data...]
addr_byte := (i2c_7bit_address << 1) | 0 # write, no R/W bit set
send()(peer -> QEMU) prefixes the outgoing SMBus/MCTP bytes withtarget_address(the BMC-side SMBus address to master-write to, required whenmaster=True) and transmits the WRITE frame immediately.recv()(QEMU -> peer) strips the leadingaddr_byte(this endpoint's own address, as written to by the BMC mastering the bus) and parses the remainder as aSmbusTransportPacket.
hn_config = {
"context": {
"physical_address": {"address": 0x10},
"supported_msg_types": [], # e.g. MsgTypes.CTRL
"assigned_eid": 66,
},
"config": {
"type": ConfigTypes.I2CStream,
"host": "localhost",
"port": 5574,
"name": "HN",
"master": True,
"target_address": 0x10,
},
}
hn = EndpointManager.from_config(hn_config)
See docs/examples/l4a40_qemu_stream.py
for a complete, runnable example.
QEMU side
QEMU listens (server=on) and PyMCTP connects as the TCP client, one port
per endpoint/bus:
-device i3c-target-remote,bus=<bus>,port=<N>,server=on
-device i2c-target-remote,bus=<bus>,address=0x<NN>,port=<N>,server=on
Add master=on to have QEMU master the (virtual) I2C bus on our behalf
instead of acting as the slave/target (peer-as-master / multi-master, like
the old i2c-netdev transport) — pair this with master=True /
target_address=<BMC addr> in the matching I2CStreamSocketConfig:
-device i2c-target-remote,bus=<bus>,address=0x<NN>,port=<N>,server=on,master=on
When QEMU itself runs inside Docker, publish each stream port with its own
-p mapping so PyMCTP (running outside the container) can connect, e.g.
-p 5556:5556 -p 5570:5570.
Auto-Registration
This package automatically registers exercisers with pymctp when installed, including:
qemu-i2c: QemuI2CNetDevSocketqemu-i3c: QemuI3CCharDevSocketqemu-i3c-stream: QemuI3CStreamSocketqemu-i2c-stream: QemuI2CStreamSocket
License
MIT
Metadata
Release files for pymctp-exerciser-qemu 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pymctp_exerciser_qemu-0.3.0.tar.gz | 23.4 kB | With provenance | Details for pymctp_exerciser_qemu-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pymctp_exerciser_qemu-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for pymctp_exerciser_qemu-0.3.0-py3-none-any.whl |
Total release size: 55.8 kB
Release files / pymctp_exerciser_qemu-0.3.0.tar.gz
| Download URL | pymctp_exerciser_qemu-0.3.0.tar.gz |
|---|---|
| Size | 23.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb88ee76d785804f115a353ec01fb6a7ed7267ab63eb054c98776d575b655640
|
|
BLAKE2b-256 checksum How to use checksums |
664b672b8779dfd25566ea75cf8ba50cf94fb351ed81b2fa9d5ac9183cc25aaa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency logRelease files / pymctp_exerciser_qemu-0.3.0-py3-none-any.whl
| Download URL | pymctp_exerciser_qemu-0.3.0-py3-none-any.whl |
|---|---|
| Size | 32.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8932b861392ac784d26fdf2c95910684e254344f2848f96e8fe54ddc601f1ede
|
|
BLAKE2b-256 checksum How to use checksums |
f81fdc7302232d721439b73af43ab61a39d5c4ab786dd21c3eff6d555fff1fe3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency logSecurity for pymctp-exerciser-qemu 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pymctp_exerciser_qemu-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.