Independent CAN, ISO-TP and DBC reference implementations in containers, with one command-line contract, for interoperability testing of CAN software such as go-canbus. Nothing in this repository depends on go-canbus.
Every image runs one upstream stack behind the same commands, flags, JSON
documents and exit codes (container contract,
JSON Schemas). A self-test runs the stacks against each other on
Linux virtual CAN (vcan), so a test suite can trust a reference before it
trusts a result against it.
| Adapter | Upstream | Version | Language | Licence | What it exercises | Operations |
|---|---|---|---|---|---|---|
canutils |
linux-can/can-utils | v2025.01 | C | GPL-2.0-only OR BSD-3-Clause | Kernel CAN_RAW (cansend, candump, canplayer); kernel CAN_ISOTP (isotpsend, isotprecv) |
send, receive, capture, replay, isotp-send, isotp-receive |
pythoncan |
python-can | 4.6.1 | Python | LGPL-3.0-only | Kernel CAN_RAW through Python's socket module; slcan (serial-line CAN) through pyserial; python-can's log readers/writers (candump, Vector ASC and BLF, PEAK TRC, CSV) |
send, receive, capture, replay, log-convert |
socketcanrs |
socketcan-rs (crate socketcan) |
4.0.0 | Rust | MIT | Kernel CAN_RAW through libc/socket2 |
send, receive |
scapy |
Scapy | 2.8.0 | Python | GPL-2.0-only | Kernel CAN_RAW (NativeCANSocket) with Scapy's own frame codec |
send, receive |
pythoncanisotp |
python-can-isotp | 2.0.7 | Python | MIT | Userspace ISO-TP state machine over python-can | isotp-send, isotp-receive |
cantools |
cantools | 45.1.1 | Python | MIT | DBC and AUTOSAR ARXML parser, signal codec | decode, encode |
canmatrix |
canmatrix | 1.3.3 | Python | BSD-2-Clause | DBC/KCD/ARXML parser and signal codec | decode, encode, convert (KCD, ARXML → DBC) |
Capabilities per image (CAN FD, BRS, ESI, remote frames, filters, ISO-TP
address modes, DBC constructs): docs/CAPABILITIES.md
and print-capabilities.
- The four raw-CAN clients (can-utils, python-can, socketcan-rs, Scapy) are
independently written userspace programs, but all of them use the same
Linux SocketCAN
CAN_RAWimplementation in the kernel. They are independent in how they build, parse and present frames (identifier flags, DLC handling, FD flags, filters, socket options, log formats), not in CAN controller or bus behaviour. None of them is a CAN controller. - The two ISO-TP implementations are genuinely independent: the Linux
kernel's
CAN_ISOTP(driven by can-utils) and python-can-isotp's pure userspace state machine. - cantools and canmatrix are independent DBC parsers and codecs.
On Linux with the CAN modules (Ubuntu: linux-modules-extra-$(uname -r)):
make vcan # vcan0 and vcan1, CAN FD capable (sudo)
make images # every image for this machine's architecture
make smoke interop # contract smoke test, reference-to-reference self-testOn macOS or with Docker Desktop (no CAN in its kernel): make images smoke selftest-dbc runs everything that does not need a CAN interface.
Use a published image directly:
docker run --rm --network host ghcr.io/otfabric/canbus-interop-canutils:v0.1.0 \
receive --interface vcan0 --count 1 --fd
echo '{"id":291,"fd":true,"brs":true,"len":12,"data":"000102030405060708090a0b"}' |
docker run --rm -i --network host ghcr.io/otfabric/canbus-interop-socketcanrs:v0.1.0 send --fdCAN interfaces belong to a network namespace and ordinary Docker networks do
not carry CAN, so containers run with --network host against vcan
interfaces of the host namespace (docs/CONTAINER_CONTRACT.md).
ghcr.io/otfabric/canbus-interop-otfabric is go-canbus behind the same contract,
so you can test your stack against ours the way we test ours against yours.
Despite the name it shares with the reference images, it is not an independent
implementation and not part of a release of this repository, so its tags are
go-canbus versions: see own/go-canbus/README.md.
scripts/interop.sh <adapter>... (make interop; the engine is
scripts/selftest.py, TESTING.md) runs, capability driven:
-
raw: every sender against every receiver for each frame fixture (11-bit, 29-bit, every classical length, every CAN FD length with and without BRS, ESI, remote frames, a paced 2000-frame sequence checked for order and loss), an unpaced burst, kernel filters (exact, masked, standard or extended only, inverted, joined), local loopback off, receive own messages, four receivers at once, capture and replay across stacks, malformed frame documents, missing interface, interface down and up.
-
isotp: kernel ↔ python-can-isotp in both directions: single frames, multi-frame up to 4095 bytes, first-frame escape (5000 bytes), block sizes, STmin in ms and µs, padding, extended and mixed addressing, 29-bit identifiers, CAN FD (SF escape, 64-byte frames), missing flow control, and hand-made frame sequences (wrong sequence number, consecutive frame without first frame, empty single frame) injected by a raw-CAN adapter.
-
dbc: cantools and canmatrix decode and encode the DBC fixtures and the ARXML fixtures and must agree byte for byte and value for value; KCD and ARXML fixtures are converted by canmatrix and decoded by both. Accepted differences are listed in tests/known-differences.tsv and reported as
known, never aspass. Any other codec (theotfabricimage) must give, for every frame and message, the result of at least one of the two oracles; ARXML multiplexing and PDU offsets are checked against the values AUTOSAR defines. -
logs: python-can's ASC, BLF, TRC and CSV writers and readers: the committed log fixtures read back as committed, and the losses of each format match docs/LOG_FORMATS.md.
A scenario a stack cannot do is reported as skip with the reason. Results
of the latest run: docs/COMPATIBILITY.md.
| Document | Content |
|---|---|
| docs/CONTAINER_CONTRACT.md | Commands, flags, documents, exit codes |
| docs/CAPABILITIES.md | Capability matrix, with the evidence for each value |
| docs/COMPATIBILITY.md | Self-test results |
| docs/FIXTURES.md | Frame, DBC, KCD, ARXML and log fixtures |
| docs/LOG_FORMATS.md | What python-can keeps of each log format |
| INTEROPERABILITY.md | How to test an implementation against these images; what vcan can and cannot show |
| TESTING.md | Running the tests |
| LIMITATIONS.md | What is not covered |
| SECURITY.md | Reporting, image hardening, safety of CAN traffic |
| CONTRIBUTING.md | Adding an adapter, changing the contract |
| RELEASE.md / CHANGELOG.md | Releases |
| THIRD_PARTY_NOTICES.md | Upstream licences |
The adapters, scripts, schemas and fixtures of this repository are MIT licensed (LICENSE). Each image also contains its upstream stack under that stack's licence (THIRD_PARTY_NOTICES.md); the canutils image includes the source code of its GPL-2.0 binaries.