uD3TN Integration
CSPCL ships with a ready-to-use Convergence Layer Adapter (cla_csp) that plugs into uD3TN, allowing uD3TN to exchange BP7 bundles over CSP on two transports: ZMQHUB (virtual/Ethernet-tunnelled) and CAN (SocketCAN).
Architecture
aap2-send / aap2-receive
|
v
uD3TN (Bundle Processor)
|
v
cla_csp <--- components/cla/posix/cla_csp.c
|
v
CSPCL <----- external/cspcl/cspcl.c
|
v
libcsp
|
+-- ZMQHUB interface ---> ZMQ Hub Broker (tcp://:6000 / :7000)
|
+-- SocketCAN interface ---> vcan0 / can0
Prerequisites
Common
| Requirement | Notes |
|---|---|
| uD3TN source | git clone https://gitlab.com/d3tn/ud3tn.git |
| libcsp v1.6 | Built with the appropriate interface(s) enabled – see below |
| Build tools | gcc, make, cmake |
ZMQHUB transport
| Requirement | Notes |
|---|---|
| libcsp v1.6 | Built with --enable-if-zmqhub |
| Python 3 + pyzmq | pip3 install pyzmq – needed to run the broker |
CAN transport
| Requirement | Notes |
|---|---|
| libcsp v1.6 | Built with --enable-can-socketcan |
| SocketCAN kernel modules | vcan for virtual testing, or a real CAN adapter (e.g. Peak, Kvaser) |
can-utils (optional) | candump / cansend for low-level debugging |
Building libcsp
cd /path/to/libcsp
# ZMQHUB only
python3 waf configure --enable-if-zmqhub
python3 waf build
# CAN (SocketCAN) only
python3 waf configure --enable-can-socketcan
python3 waf build
# Both (recommended for development)
python3 waf configure --enable-can-socketcan --enable-if-zmqhub
python3 waf build
libcsp v1.6 requires Python 3.11+ for the waf build system.
Applying the Patch
cd /path/to/ud3tn
sed -i 's|/home/mathias/libcsp-src|/path/to/libcsp-src|g' \
/path/to/cspcl/ud3tn-integration/ud3tn-cla-csp.patch
git apply /path/to/cspcl/ud3tn-integration/ud3tn-cla-csp.patch
make
Manual File Copy (Alternative)
export CSPCL=/path/to/cspcl UD3TN=/path/to/ud3tn
cp $CSPCL/src/cspcl.c $UD3TN/external/cspcl/
cp $CSPCL/src/cspcl.h $UD3TN/external/cspcl/
cp $CSPCL/ud3tn-integration/src/cla_csp.c $UD3TN/components/cla/posix/
cp $CSPCL/ud3tn-integration/src/cla_csp.h $UD3TN/include/cla/
cd $UD3TN && make
CLA Configuration
The transport and its parameters are selected via the --cla argument passed to uD3TN.
--cla "csp:<local_addr>,<port>[,<iface>]"
<iface> value | Transport | Parameter used |
|---|---|---|
| (omitted) | ZMQHUB | broker at localhost (default) |
zmqhub | ZMQHUB | broker at localhost (default) |
zmqhub:<host> | ZMQHUB | broker at <host> (hostname or IP) |
can | SocketCAN | device vcan0 (default) |
can:<iface> | SocketCAN | device <iface> (e.g. can0, vcan1) |
loopback | Loopback | built-in CSP loopback (no external process needed) |
Examples
# ZMQHUB on localhost (default)
--cla "csp:1,10"
# ZMQHUB on a remote machine
--cla "csp:1,10,zmqhub:192.168.1.10"
# Virtual CAN on the default vcan0 interface
--cla "csp:1,10,can"
# Physical CAN adapter
--cla "csp:1,10,can:can0"
# Local loopback (single-machine testing without a broker)
--cla "csp:1,10,loopback"
Running a Two-Node Test
Use the helper script for a guided walkthrough including diagnostics:
# ZMQHUB transport
./tools/simple_bundle_transfer.sh --transport zmqhub
# CAN transport
./tools/simple_bundle_transfer.sh --transport can
Or follow the steps below manually.
ZMQHUB
1. Start the broker
python3 tools/zmqhub_broker.py -v
2. Start Node A (CSP addr 1)
ud3tn --node-id dtn://a.dtn/ --aap-port 4242 \
--aap2-socket 1.aap2.socket --cla "csp:1,10"
3. Start Node B (CSP addr 2)
ud3tn --node-id dtn://b.dtn/ --aap-port 4243 \
--aap2-socket 2.aap2.socket --cla "csp:2,10"
CAN (SocketCAN)
1. Set up the virtual CAN interface (skip for physical CAN)
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
2. Start Node A (CSP addr 1)
ud3tn --node-id dtn://a.dtn/ --aap-port 4242 \
--aap2-socket 1.aap2.socket --cla "csp:1,10,can"
3. Start Node B (CSP addr 2)
ud3tn --node-id dtn://b.dtn/ --aap-port 4243 \
--aap2-socket 2.aap2.socket --cla "csp:2,10,can"
Both nodes share the same CAN bus (
vcan0), so no broker process is needed.
Common steps (both transports)
4. Configure route A to B
aap2-config --socket 1.aap2.socket \
--schedule 1 3600 100000 dtn://b.dtn/ csp:2
5. Start receiver on B
aap2-receive --socket 2.aap2.socket --agentid bundlesink
6. Send a bundle from A
aap2-send --socket 1.aap2.socket dtn://b.dtn/bundlesink 'hello,world!'
Troubleshooting
Port 10 already in use – a previous uD3TN process left the CSP port bound.
pkill -f ud3tn && rm -f /tmp/*.aap2.socket
No packets at the ZMQ broker – verify both nodes connect to the same host/ports and that libcsp was built with --enable-if-zmqhub.
CAN frames not appearing – verify vcan0 is up (ip link show vcan0) and that libcsp was built with --enable-can-socketcan. Use candump vcan0 to inspect raw frames.
Bundle not delivered – confirm the route was scheduled with aap2-config and that the agent ID in the receiver matches the service portion of the destination EID.
Enable debug logging
export UD3TN_LOG_LEVEL=debug
Look for these log lines in uD3TN output:
CSP: Initialized with local address X, port YCSP: Connecting to ZMQHUB broker at '<host>'CSP: Opening CAN interface '<iface>'CSP: Starting scheduled contact to csp:XCSP: Sending N bytes to csp:XCSP: RX task started