Skip to content

Virtual CAN on Linux

Virtual CAN (vcan) allows you to create software-only CAN buses for testing and development without physical hardware.

Setting Up Virtual CAN

Prerequisites

Ensure the vcan kernel module is loaded:

sudo modprobe vcan

Creating a Virtual Interface

Create a virtual CAN interface named vcan0:

sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

Verifying the Setup

Check that the interface was created:

ip link show vcan0

You should see output similar to:

5: vcan0: <NOARP,UP,LOWER_UP> mtu 16 qdisc noqueue state UNKNOWN mode DEFAULT
    link/can

Using Virtual CAN with Sockcan

Standalone Mode

Create a virtual CAN network with multiple applications:

# app1.py - Receiver
from sockcan import SocketcanConfig, connect_to_socketcan, build_recv_func

config = SocketcanConfig(channel="vcan0")
sock = connect_to_socketcan(config)
recv = build_recv_func(sock)

print("Waiting for messages on vcan0...")
msg = recv()
print(f"Received: ID={msg.arbitration_id:#x}, Data={msg.data.hex()}")
# app2.py - Sender
from sockcan import SocketcanConfig, connect_to_socketcan, build_send_func

config = SocketcanConfig(channel="vcan0")
sock = connect_to_socketcan(config)
send = build_send_func(sock, expects_msg_cls=False)

send(0x123, b'\xde\xad\xbe\xef', False)
print("Message sent!")

Run both applications in separate terminals - messages will be transmitted between them.

python-can Interoperability Layer

Use virtual CAN with python-can's interface:

import can
from sockcan.interop import hijack_python_can

hijack_python_can()

bus = can.Bus(interface="socketcan", channel="vcan0")

# Send a message
msg = can.Message(
    arbitration_id=0x456,
    data=[1, 2, 3, 4],
    is_extended_id=False,
)
bus.send(msg)

# Receive a message
received = bus.recv(timeout=1.0)
print(f"Received: {received}")

Using Real CAN Hardware

When you have real CAN hardware connected (e.g., on interface can0), simply change the channel name:

Standalone Mode

from sockcan import SocketcanConfig, connect_to_socketcan, build_send_func

config = SocketcanConfig(channel="can0")  # Use real interface
sock = connect_to_socketcan(config)
send = build_send_func(sock, expects_msg_cls=False)

send(0x100, b'\x01\x02\x03\x04', False)
print("Message sent to real CAN bus!")

python-can Interoperability Layer

import can
from sockcan.interop import hijack_python_can

hijack_python_can()

bus = can.Bus(interface="socketcan", channel="can0")
msg = can.Message(arbitration_id=0x789, data=[0x11, 0x22, 0x33])
bus.send(msg)

Multiple Virtual CAN Interfaces

Create multiple virtual interfaces for complex testing scenarios:

sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
sudo ip link add dev vcan1 type vcan
sudo ip link set up vcan1

Isolated Testing

Applications on different vcan interfaces are isolated from each other:

# app_on_vcan0.py
config = SocketcanConfig(channel="vcan0")
sock = connect_to_socketcan(config)

# app_on_vcan1.py
config = SocketcanConfig(channel="vcan1")
sock = connect_to_socketcan(config)

Bridging Virtual and Physical CAN

Use can-utils cangw or the SocketcanServer to bridge virtual and physical CAN:

from sockcan.daemon import SocketcanServer, BusParameters
from sockcan import build_send_func, build_recv_func

# Bridge vcan0 to real CAN hardware on can0
with SocketcanServer.factory(
    BusParameters(channel="can0", interface="socketcan")
) as server:
    vcan_sock = server.subscribe()
    recv = build_recv_func(vcan_sock)
    send = build_send_func(vcan_sock, expects_msg_cls=False)

    # Messages from can0 appear on vcan_sock
    msg = recv()

Cleanup

Remove a virtual CAN interface when no longer needed:

sudo ip link delete vcan0

Or remove all vcan interfaces:

sudo ip link show | grep vcan | cut -d: -f2 | xargs -I{} sudo ip link delete {}

Troubleshooting

Interface Not Found

OSError: [Errno 19] No such device

Solution: Create the virtual interface first:

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

Permission Denied

PermissionError: [Errno 1] Operation not permitted

Solution: Run with sudo or add your user to the can group:

sudo usermod -aG can $USER

Messages Not Received

Possible causes: 1. Interface not in UP state 2. Loopback mode is OFF 3. Different channel names

Solution: Verify interface state:

ip link show vcan0
# Should show: <NOARP,UP,LOWER_UP>