Part 4
showed ACF-CAN tunneling using Open1722’s user-space example applications.
This part goes one level deeper: the
Open1722 Linux kernel module
(examples/acf-can/linux-kernel-mod/), which implements ACF-CAN tunneling
directly in the kernel — not using the two veth interfaces on a single
machine from the upstream example, but between two physical
BeagleBone
Black boards connected via an Ethernet cable.
This post is meant as a self-contained hands-on project, grounded in the
real |
Architecture: ACF-CAN as an ordinary SocketCAN interface
The trick behind the kernel module: from user space, there’s no difference
between a real CAN driver (hardware CAN controller) and the acfcan network
device — both serve the normal Linux SocketCAN interface. cansend/candump
work identically, regardless of whether there’s a real CAN bus or ACF-CAN
over Ethernet behind them.
| Feature | Status per the Open1722 README |
|---|---|
CAN and CAN FD | Supported |
Configurable stream and bus ID | Supported |
NTSCF | Supported |
Sending and receiving | Supported |
TSCF | Not yet supported |
CAN-BRIEF | Not yet supported |
Batching (multiple ACF-CAN messages per frame) | Not yet supported — currently exactly one ACF-CAN message per IEEE 1722 frame |
Per its own README, the kernel module is explicitly "in active
development" — it deliberately only supports NTSCF, not TSCF, and doesn’t
yet bundle multiple ACF messages per frame (unlike the
|
Cross-compiling against the BeagleBone Black’s Yocto kernel
Instead of the Ubuntu host described in the Open1722 README, this cross-compiles against the Yocto kernel already shown in the kernel module series:
source /opt/poky/*/environment-setup-cortexa8hf-neon-poky-linux-gnueabi
cd Open1722/examples/acf-can/linux-kernel-mod
export CONFIG_ACF_CAN=m
make KDIR=$KERNEL_SRC$KERNEL_SRC points to the configured kernel source tree of the Yocto build
(tmp/work-shared/beaglebone-yocto/kernel-source) — exactly the same kernel
version and configuration running on the target, otherwise loading fails
with a version mismatch (see the
kernel module
post).
This build step is identical on both boards — the module has to be built (or at least copied) and loaded individually on each BeagleBone Black. |
Loading the module
On both boards, first load the CAN subsystem dependency, then the module itself:
sudo modprobe can
sudo insmod acfcan.ko
|
Setup: two physical interfaces instead of two veth pairs
The upstream example in the Open1722 README shows two acfcan interfaces
connected via a veth pair on one machine (ip link add dev mon1 type
veth peer name mon2). Here, the same principle happens instead over a real
Ethernet cable between two boards.
On board A
sudo ip link add dev ecu0 type acfcan
sudo ip link set ecu0 mtu 72
# ethif points at the board's real eth0, not a veth interface
echo -n "eth0" | sudo tee /sys/class/net/ecu0/acfcan/ethif
# dstmac is board B's real MAC address
echo -n "<Board B's MAC address>" | sudo tee /sys/class/net/ecu0/acfcan/dstmac
echo -n "cafe11" | sudo tee /sys/class/net/ecu0/acfcan/tx_streamid
echo -n "dead22" | sudo tee /sys/class/net/ecu0/acfcan/rx_streamid
sudo ip link set up ecu0On board B
sudo ip link add dev ecu1 type acfcan
sudo ip link set ecu1 mtu 72
echo -n "eth0" | sudo tee /sys/class/net/ecu1/acfcan/ethif
echo -n "<Board A's MAC address>" | sudo tee /sys/class/net/ecu1/acfcan/dstmac
echo -n "dead22" | sudo tee /sys/class/net/ecu1/acfcan/tx_streamid
echo -n "cafe11" | sudo tee /sys/class/net/ecu1/acfcan/rx_streamid
sudo ip link set up ecu1Board A’s |
Test: real CAN traffic between two boards
# Listen on board B
candump ecu1
# Send on board A
cansend ecu0 123#DEADBEEFThe message shows up on board B, even though there’s no real CAN bus
between the boards — it was tunneled entirely over the Ethernet cable as an
ACF-CAN message. Unlike the upstream veth example, this isn’t a loopback
on a single machine, but real network traffic between two physical devices.
Running |
Diagnostics
dmesg --follow
# Enable dynamic debug, if the kernel supports it
echo 'module acfcan +p' | sudo tee /sys/kernel/debug/dynamic_debug/control| Problem | Typical cause |
|---|---|
| Forgot |
No traffic visible in |
|
| Module not built against exactly the kernel running on the board — see the kernel module post |
Secure Boot prevents loading | Rarely relevant in practice for a self-built Yocto kernel on the BeagleBone Black — more relevant for Ubuntu hosts with Secure Boot enabled |
Conclusion: the first building block for a zonal gateway experiment
This setup — a BeagleBone Black transparently tunneling its own (simulated) CAN subnet over a TSN-capable Ethernet backbone to a "central" node — is, in miniature, exactly the scenario from Part 2: a partially migrated zonal architecture where a zonal controller transparently tunnels legacy CAN traffic without the actual CAN ECUs noticing anything. Two BeagleBone Black boards and an Ethernet cable are enough to make this principle tangible before moving on to a real, multi-layered vehicle network.
Summary
| Aspect | Key takeaway |
|---|---|
Architecture |
|
Build | Cross-compile against the Yocto kernel source tree, exactly as in the
kernel module fundamentals post — |
Setup | Two physical |
Test |
|
Takeaway | A small, concretely followable example of the zonal-gateway scenario from Part 2 — not an AUTOSAR BSW module, but the same underlying principle |