Update CANBUS.md for Bookworm
This is a PR to add the steps needed for bookworm installations to enable the can0 network for host hardware
Thanks James
Thanks for working on this. For what it is worth, I'm not sure our audience will immediately know what "bookworm" and "bullseye" are. Can we just change to the new system and remove the old recommendations? (Or are there OS distros out there that don't support the new system?) Alternatively, is there some package on debian bookworm that could be installed so that it works with the old system?
Cheers, -Kevin
Can we just change to the new system and remove the old recommendations?
I'm not sure if I recommended this as a general practice. From what I read, it depends on the systemd version. There seem to be bugs and missing functionality if it is too old.
Additionally, I wouldn't mix different network management methods. If the distribution's standard method is the legacy interfaces approach, it's probably best to stick with it.
Probably the easiest way to identify which approach to use is by checking /etc/network. If there is no interfaces or interfaces.d, then the systemd method needs to be used.
Regarding the link file, I have noticed something a bit uncomfortable. Depending on the distribution and type of CAN adapter, the OS might automatically assign a link file. Probably this makes sense as the link files essentially are just some sort of udev rule.
On my side, an example looks like this:
# networkctl status can0
● 3: can0
Link File: /usr/lib/systemd/network/73-usb-net-by-mac.link
Network File: /etc/systemd/network/80-can.network
State: carrier (configured)
Online state: unknown
Type: can
Kind: can
Path: platform-5310000.usb-usb-0:1.5:1.0
Driver: gs_usb
Vendor: OpenMoko, Inc.
Model: Geschwister Schneider CAN adapter
MTU: 16
QDisc: pfifo_fast
Number of Queues (Tx/Rx): 1/1
Activation Policy: up
Required For Online: no
In this case, creating a /etc/systemd/network/80-can.link file to modify the TX queue length wouldn't do anything. I had to modify the link file as assigned by the OS.
Maybe a safe way to handle this:
- Bring up the network via the
.networkfile. - Use
networkctl status can0to show the details. - If no link file is assigned, create one with the appropriate content. If one exists, modify it to add the relevant section.
Thanks @Sineos @KevinOConnor
Unfortunately we are living in a two tier situation where people are still installing legacy or using pre made images like mainsailOS which is still Bullseye or installing newest bookworm versions of Debian. I am not sure how we deal with that. It is not the intention to provide instructions to completely change the networking system on someones device, that is likely way out of the docs remit IMO
We tried 3 methods of setting up can0 in Bookwork,
a)create the network file, and apply txqueuelength via a service that just runs ifconfig can0 txqueuelen 128 as an ExecStart with a WantedBy=sys-subsystem-net-devices-can0.device
b) Esotericals way of applying a UDEV rule
c) using a link file as detailed here
I went with c) for ease of setup more than anything, I was not aware that a link file would be applied if no can0 already exists though, @Sineos what distro is this?
Thanks James
My recommendation is to avoid naming distributions completely, as it will either be incomplete or outdated.
For me, the best approach is for the user to check the existence of the interfaces file. If it is available, use the traditional method; if not, go for systemd.
The machines I have set up using this approach all work pretty flawlessly with the .network and .link setup. The example above, where the .link is pre-allocated by the OS, is from Armbian 24.11 on Ubuntu 24.04. I have seen machines that would leave the .link empty and expect it to be defined manually. Unfortunately, I have not been able to identify the logic behind this.
As such, I'd recommend bringing up the interface with the .network file only and checking what the OS is expecting. The .link anyway is only needed to modify the queue length, so it can be easily adapted in the second step.
With the command
ip -details -statistics link show can0
you can both check for the queue length as well as any RX / TX errors, so it might be worthwhile adding it.
Thats all well and good and makes sense, but we have to make it succinct and doable by the average uninformed user. i don't like giving them an "either or" in the first place, as they wont read the or and decide its broken because the first thing didnt work. It is a quandary how we best approach documenting multiple systems and ways
Thanks James
I agree, but I'm afraid that there is no such thing as a free lunch.
AFAIK, the ability to specify TX queue length has only been added in systemd from version 248 onwards. This already takes Bullseye out of the equation.
See https://github.com/systemd/systemd/blob/5dc89b327f2361c2a8a43c74871ae5bdd6a6c814/NEWS#L6892-L6893
@JamesH1978, if your main concern is user-facing complexity, a potential solution could be to automate setting up the interface via a script. The description could reference the script as well as the manual approach for those who are interested or more advanced.
FWIW, I hacked together a PoC. If it is deemed useful, please go ahead and add it to this PR. I'm not interested in any copyrights whatsoever.
"Legacy" Method:
# python3 linux_setup_can0.py
[*] Checking if the script is run as root...
[+] Script is running as root.
[*] Please enter the CAN bitrate. Allowed values are 250000, 500000, 1000000.
CAN Bitrate (default: 500000):
[*] Checking if /etc/network/interfaces.d exists...
[+] /etc/network/interfaces.d exists.
[*] Creating /etc/network/interfaces.d/can0...
[+] /etc/network/interfaces.d/can0 created successfully.
[*] Bringing up can0 interface...
RTNETLINK answers: Connection timed out
ifup: failed to bring up can0
[-] First attempt to bring up can0 interface failed: Command '['ifup', 'can0']' returned non-zero exit status 1.
[*] Waiting 10 seconds before retrying...
[+] can0 interface brought up successfully on the second attempt.
[*] Checking if can0 interface is up...
[+] can0 interface is up and running.
[+] CAN interface configuration completed successfully.
[*] A reboot is recommended to ensure all changes take effect.
systemd with pre-allocated link file
# python linux_setup_can0.py
[*] Checking if the script is run as root...
[+] Script is running as root.
[*] Please enter the CAN bitrate. Allowed values are 250000, 500000, 1000000.
CAN Bitrate (default: 500000):
[*] Checking if /etc/network/interfaces.d exists...
[-] /etc/network/interfaces.d does not exist.
[*] Checking systemd version...
[+] Systemd version 255 is greater than 248.
[*] Creating /etc/systemd/network/80-can.network...
[+] /etc/systemd/network/80-can.network created successfully.
[*] Reloading systemd network configuration...
[+] Systemd network configuration reloaded successfully.
[*] Checking if can0 interface is up...
[+] can0 interface is up and running.
[*] Checking if a .link file is specified for can0...
[+] Link file found: /usr/lib/systemd/network/73-usb-net-by-mac.link
[*] Modifying /usr/lib/systemd/network/73-usb-net-by-mac.link...
[+] /usr/lib/systemd/network/73-usb-net-by-mac.link modified successfully.
[*] Reloading systemd network configuration...
[+] Systemd network configuration reloaded successfully.
[*] Checking if can0 interface has qlen set to 128...
[+] can0 interface has qlen set to 128.
[+] CAN interface configuration completed successfully.
[*] A reboot is recommended to ensure all changes take effect.
Thanks for working on this.
FWIW, I'd prefer not to add additional system installation scripts to the Klipper repo - it's too much of an ongoing maintenance burden.
I'm not sure what the best way forward is.
It is not the intention to provide instructions to completely change the networking system on someones device, that is likely way out of the docs remit IMO
Agreed.
We tried 3 methods of setting up can0 in Bookwork
Maybe use Esoterical's udev method for setting txqueuelength, and then alert the user to install either /etc/network/interfaces.d/can0 (without the up ip link set $IFACE txqueuelen 128) or /etc/systemd/network/80-can0.network .
Not sure. -Kevin
Maybe use Esoterical's udev method for setting txqueuelength, and then alert the user to install either
/etc/network/interfaces.d/can0(without theup ip link set $IFACE txqueuelen 128) or/etc/systemd/network/80-can0.network.
From the user perspective, I see no benefit in making the ifupdown method more complex by introducing udev rules.
Since all Debian and Debian-like distributions use systemd in their currently stable releases, I would describe systemd first and leave the ifupdown method as is. It will likely disappear sooner rather than later anyway.
Finally, the Linux side of Klipper will always introduce additional complexity. Luckily, today KIAUH hides most of it, acting as an excellent Swiss Army Knife for Klipper installations. If it did not exist, the need for installation scripts and helpers would be much more prominent.
As far as i know, and as you say @Sineos all current debian versions should be able to use systemd networkd, so we could just drop the old info completely. i will need to install a copy of mainsailOS on bullseye to check this works
Thanks James
From my gut feeling and reading a lot about this topic, I'd not recommend doing this:
- There seem to be quite a few bugs around the network portion of systemd in older versions.
- There has been a lot of movement between the old stable distribution (e.g., Bullseye) with versions around 247 and the current stable versions (e.g., Bookworm) with versions around 255.
- No distribution that I know of, before the currently stable ones, "dared" to switch to systemd-networking - probably for a reason.
As such, I personally also do not agree with Esoterical's approach of recommending it unconditionally and mixing ifupdown-based distributions with the systemd approach. The ifupdown method is battle-tested and apparently stable. I'm not sure if a bit of documentation simplification is worth potentially introducing subtle issues.
I ran into this issue yesterday while setting up CAN and was going to follow these instructions: https://github.com/Esoterical/voron_canbus/blob/main/Getting_Started.md
I tested esoterical's instructions but ended up with a system that didn't sync time with ntp anymore (it broke systemd-timesyncd), as described here: https://github.com/Esoterical/voron_canbus/issues/92 The "fix" added a second ip address to my pi (!) so reverted those changes.
The guide in this PR worked perfectly, thanks @JamesH1978
I spoke too soon, ntp system time sync was also broken using @JamesH1978's guide and @Sineos script. System time on RPI wouldn't sync at startup and timeout after 2 mins :(
thijs@prusa:~ $ timedatectl status
Local time: Fri 2025-02-14 03:45:15 CET
Universal time: Fri 2025-02-14 02:45:15 UTC
RTC time: n/a
Time zone: Europe/Amsterdam (CET, +0100)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
thijs@prusa:~ $ networkctl list
IDX LINK TYPE OPERATIONAL SETUP
1 lo loopback carrier unmanaged
2 eth0 ether routable unmanaged
3 can0 can carrier configured
3 links listed.
thijs@prusa:~ $ journalctl -fu systemd-networkd-wait-online.service
Feb 14 03:41:30 prusa systemd[1]: Starting systemd-networkd-wait-online.service - Wait for Network to be Configured...
Feb 14 03:43:31 prusa systemd-networkd-wait-online[308]: Timeout occurred while waiting for network connectivity.
Feb 14 03:43:31 prusa systemd[1]: systemd-networkd-wait-online.service: Main process exited, code=exited, status=1/FAILURE
Feb 14 03:43:31 prusa systemd[1]: systemd-networkd-wait-online.service: Failed with result 'exit-code'.
Feb 14 03:43:31 prusa systemd[1]: Failed to start systemd-networkd-wait-online.service - Wait for Network to be Configured.
I tried the workaround here:
sudo systemctl edit systemd-networkd-wait-online.service
And use following to override ExecStart and adding --interface=eth0(as well as an extra ExecStart= line before that):
### Editing /etc/systemd/system/systemd-networkd-wait-online.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --interface=eth0
### Lines below this comment will be discarded
But it didn't work either.
What did work (knocks on wood), found here:
Add following to /etc/systemd/network/80-can.network:
[Link]
RequiredForOnline=no
And reboot.
Check timedatectl statusand it shows it synced:
Local time: Sat 2025-02-15 20:59:01 CET
Universal time: Sat 2025-02-15 19:59:01 UTC
RTC time: n/a
Time zone: Europe/Amsterdam (CET, +0100)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Finally, back to printing.
Add following to
/etc/systemd/network/80-can.network:[Link] RequiredForOnline=no
This is correct. This is one of the bugs I mentioned and is one of the reasons for my warning not to use older versions. It has been fixed with v256 and AFAIK also backported in some distributions.
On a side note: I'd always recommend running a full-fledged time sync service like chrony or the NTP daemon, but that's generally unrelated to this discussion.
It has been fixed with v256 and AFAIK also backported in some distributions.
Thanks for the feedback. This RpiOS Lite downloaded 2 days ago:
$ uname -a
Linux prusa 6.6.74+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.74-1+rpt1 (2025-01-27) aarch64 GNU/Linux
shows an outdated systemctl indeed:
$ systemctl --version
systemd 252 (252.33-1~deb12u1)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified
I'd always recommend running a full-fledged time sync service like chrony or the NTP daemon, but that's generally unrelated to this discussion.
yea, I always use an ds3231 RTC and that would also get rid of this issue. Aslong as RequiredForOnline=no is added..
As far as i know, and as you say @Sineos all current debian versions should be able to use systemd networkd, so we could just drop the old info completely. i will need to install a copy of mainsailOS on bullseye to check this works
Thanks James
Hit this last night. It does not. "TransmitQueueLength" was added in systemd version 248, and Bullseye is running 247.
After updating to Bookworm, I found it still did not work. Those link file changes @Sineos mentioned seem to also be necessary without additional changes.
ip -j -p link show can0
[ {
"ifindex": 4,
"ifname": "can0",
"flags": [ "NOARP","UP","LOWER_UP","ECHO" ],
"mtu": 16,
"qdisc": "pfifo_fast",
"operstate": "UP",
"linkmode": "DEFAULT",
"group": "default",
"txqlen": 10,
"link_type": "can"
} ]
Update. TransmitQueueLength is only defined for the .link files, so a few changes to this PR are needed.
@Sineos there are a few possible reasons a custom link file wasn't working for you.
- I believe is uses a first match system, going from lowest to highest. If you named it "80-can.link" the "73*.link" file would match first.
- Simply doing a
networkctl reloaddoes not update which link file matches the interface. I had to reboot. - Unlike .network files, .link files can't match on
Name=....
70-can.link
[Match]
Kind=can
[Link]
NamePolicy=keep
# Added in version 248.
TransmitQueueLength=128
70-can.network
[Match]
Name=can*
# https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#[CAN]%20Section%20Options
[CAN]
BitRate=1M
RestartSec=10ms
I believe is uses a first match system, going from lowest to highest. If you named it "80-can.link" the "73*.link" file would match first.
Simply doing a
networkctl reloaddoes not update which link file matches the interface. I had to reboot.
Good information @EmperorArthur 👍 Indeed, it looks like as you said. The key seems to be that you need a "lower sequence number" (thus higher priority) than the one automatically assigned by the OS.
Thank you for your contribution to Klipper. Unfortunately, a reviewer has not assigned themselves to this GitHub Pull Request. All Pull Requests are reviewed before merging, and a reviewer will need to volunteer. Further information is available at: https://www.klipper3d.org/CONTRIBUTING.html
There are some steps that you can take now:
- Perform a self-review of your Pull Request by following the steps at: https://www.klipper3d.org/CONTRIBUTING.html#what-to-expect-in-a-review If you have completed a self-review, be sure to state the results of that self-review explicitly in the Pull Request comments. A reviewer is more likely to participate if the bulk of a review has already been completed.
- Consider opening a topic on the Klipper Discourse server to discuss this work. The Discourse server is a good place to discuss development ideas and to engage users interested in testing. Reviewers are more likely to prioritize Pull Requests with an active community of users.
- Consider helping out reviewers by reviewing other Klipper Pull Requests. Taking the time to perform a careful and detailed review of others work is appreciated. Regular contributors are more likely to prioritize the contributions of other regular contributors.
Unfortunately, if a reviewer does not assign themselves to this GitHub Pull Request then it will be automatically closed. If this happens, then it is a good idea to move further discussion to the Klipper Discourse server. Reviewers can reach out on that forum to let you know if they are interested and when they are available.
Best regards, ~ Your friendly GitIssueBot
PS: I'm just an automated script, not a human being.
@thijstriemstra
Add following to
/etc/systemd/network/80-can.network:[Link] RequiredForOnline=no
I don't know how I missed this, or when testing this I was screwing things up. Maybe I was associating the "RequiredForOnline" with previous attempts to stop the systemd-networkd-wait-online.service from making it take so long to boot (and RequiredForOnline never seemed to help with this). But just tested myself and yeah it seems to solve the timedatectl issue. Thanks so much!
@Sineos For some background info, I too completely agree that "just going to systemd-networkd" is not ideal. It's just that with how my guides are written I try to make it as "simple" as possible, and a bunch of "if your distro is this age, do this, otherwise do this" ends up being confusing. Pure systemd-networkd does seem to work across a wide spread of boards/distros. The only last niggle was the timedatectl issue but that might be sorted now. I wish I could use a .link file for the transmitqueuelen as well, but there are still a bunch of distros out in the wild (looking at you BTT) that are running systemctl 247 and the TransmitQueueLength option only came in 248. So a udev rule is at least also universal.
@Esoterical I really appreciate your guides, so thanks a lot for providing them.
Regarding the network settings, I have stated my opinion. To reiterate:
- I see no reason to force an ifupdown-based distribution to use systemd.
- Especially not for older systemd versions.
- Systemd is more complex than the ifupdown approach.
- Differentiating between them is as simple as running
ls /etc/network/interfaces. If it does not return anything, then use the systemd approach. So, from this documentation aspect, not much is gained.
Distributions with ifupdown-based networking will likely vanish sooner or later. This will give the systemd approach time to mature. Generally, my feeling is that it makes things more complicated with little to no gain (at least for the scenarios in which I use Linux), but this is how it is.
@Sineos let me add another wrinkle or two to everything.
There's actually 3 different major network management methods.
- ifupdown
- systemd-networkd
- NetworkManager
NetworkManager is designed for changing connections/WiFi, and is what GUIs use. Including KlipperScreen. Systemd-networkd is more meant for servers, or other systems where things don't change regularly/ via the GUI. Unfortunately, the wait for online services don't play nicely between them, and I had to disable systemd-networkd's service.
The second wrinkle is both of those are also designed to work even if there are files in /etc/network/interfaces.
I'll need to double check, but I'm pretty sure I've ended up with running all 3.
- ifupdown - Forgot to remove the files.
- systemd-networkd - CAN as related to this change.
- NetworkManager - Actual manager w/ KlipperScreen integration.
@Sineos let me add another wrinkle or two to everything.
There's actually 3 different major network management methods.
- ifupdown
- systemd-networkd
- NetworkManager
NetworkManager is designed for changing connections/WiFi, and is what GUIs use. Including KlipperScreen. Systemd-networkd is more meant for servers, or other systems where things don't change regularly/ via the GUI. Unfortunately, the wait for online services don't play nicely between them, and I had to disable systemd-networkd's service.
The second wrinkle is both of those are also designed to work even if there are files in /etc/network/interfaces.
I'll need to double check, but I'm pretty sure I've ended up with running all 3.
- ifupdown - Forgot to remove the files.
- systemd-networkd - CAN as related to this change.
- NetworkManager - Actual manager w/ KlipperScreen integration.
Edit:
@JamesH1978 and @KevinOConnor
Bullseye has about another year left before it's gone. We need to start pushing people to update their systems yesterday. The fact new printers are shipping with it should be called out.
https://wiki.debian.org/LTS/Bullseye
I didn't have an issue doing a live update to Bookworm, but I also ran Debian Sid and KDE Neon for years. So my standards are a bit skewed.
@EmperorArthur I'm not talking about people who are familiar with Linux and especially the shell. The reality is that the majority of users already find ls /dev/serial/by-id/* challenging. Something I do understand if my first contact with bare-bones Linux is Klipper.
@Sineos I understand. Just providing some more info.
I run Debian 12 bookworm as well, and I actually have problems with systemd-network + NetworkManager. NetworkManager is the default network manager on my RaspberryPi CM5. If I enable systemd-network to manage the CANBUS interface, it seems to cause conflicts with NetworkManager. systemd-network will also try to manage my Ethernet and WiFi devices and connections (judging from system logs), causing networking issues, slow booting, etc.
In the end, I used NetworkManager + ifupdown. With ifupdown, I only added the CANBUS interface in /etc/network/, so it only manages that. This is the most stable solution for me so far. I haven't found other working alternatives yet.
@LipuFei Here's how to get it working:
- Make sure your files look like below, and you only have the "70-can" files in "/etc/systemd/network/" folder.
- Run
systemctl enable systemd-networkd.service - Run
systemctl disable systemd-networkd-wait-online.service
/etc/systemd/networkd.conf
[Network]
[DHCPv4]
[DHCPv6]
/etc/systemd/network/70-can.link
[Match]
Kind=can
[Link]
NamePolicy=keep
TransmitQueueLength=128
/etc/systemd/network/70-can.network
[Match]
Name=can*
[CAN]
BitRate=1M
#BitRate=250K
RestartSec=10ms
#Termination=yes
You can verify systemd-networkd is correct by looking at the output of networkctl -a. Everything but the can adapter should show as "unmanaged". Disabling systemd-networkd-wait-online fixes the boot issues you were seeing.
You can verify NetworkManager is working by looking at the output of nmcli.
@EmperorArthur Just FYI, it seems adding
[Link]
RequiredForOnline=no
to the can.network file will stop the NTP time sync from failing (on some distros, don't know if it's required for all distros but I'm sure it can't hurt)