How to interact with Socket-Can?

Hi,

I’m trying to get our app to read from our Can-Bus interface card. I have the Linux driver compiled and installed in the Kernel.

But when I try to bring up the interface in the container.

root@host:/usr/src/app# ip link set emuccan0 up qlen 1000
Cannot find device "emuccan0"

On the Host OS this does work and a new emuccan0 interface shows up under ifconfig. But how do I expose it to my application container so that our app can work with it?

Hi, are you running a privileged container there?

There’s actually another active thread about CAN bus on balenaOS over here: https://forums.balena.io/t/92052

Does that help?

Yeah, that thread is mine too, but it’s about a different problem.

The complete story is I have to support two different CAN bus interface cards. One from Peak where I can’t get the driver to load in the Kernel. That other thread is about that.
My other card is from Innodisk, they ave their own driver separate from the kernel source tree. That module builds and installs fine in my kernel.

But now Balena does not give me access to the network device Linux makes for me. This thread is about that issue. I figured they are separate issues so I make different posts.

I can try raise this with the OS team to check, but can you confirm that you’re running the container in privileged most first? Just to rule out the easiest options first :slight_smile:

Fair enough :slight_smile:

Yes it’s in privileged mode.

To be precise I have all of these set on the container:

    privileged: true
    labels:
      io.balena.features.balena-socket: 'true'
      io.balena.features.dbus: 'true'
      io.balena.features.sysfs: 'true'
      io.balena.features.procfs: 'true'
      io.balena.features.kernel-modules: 'true'
    devices:
      - "/dev/ttyACM0:/dev/ttyACM0"

Thanks for confirming. What I would suggest it to provide the dmesg output for both the container and host OS, which might give us some information.

Here’s the dmesg logs for host and container.
dmesg-host.log (51.4 KB)
dmesg-container.log (40.1 KB)

Just to clarify my issue, the device driver works, it loads without error. The thing is that CAN bus interface cards are treated as network devices by Linux. And Balena, does not let me interface directly with a network device from the container.

On the Host OS I can run:

ip link set emuccan0 up qlen 1000

And this will give me the emuccan0 network interface like so:

emuccan0  Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          NOARP  MTU:16  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:10
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

This is really quite convenient because from our application code we can interact with the CAN bus using simple sockets.

But when I try to run the same ip link command from the container I get:

ip: ioctl 0x8943 failed: No such device

I suspect this is because Linux treats it as a network device and Balena is (for good reason) rather possessive about network devices.

In short I’d like to know how I can interact with the CAN bus sockets from a container.

Thanks!
Erik

Hi, you can make the same interfaces visible in the host OS to be visible in the container by adding this to service configuration:

network_mode: "host",
privileged: true

See: https://www.balena.io/docs/learn/develop/runtime/#network

Yes, that does allow me to reach the canbus interface.
But now my app can’t communicate with the other containers anymore.
Should I abandon isolation and switch the other containers to host mode as well and bind to 127.0.0.1?

No need to switch other containers to host mode. You can bind a host port in bridged container. Like this:

services
  a
    network_mode: "host",
    privileged: true
  b
    ports:
      - 8080:80
  c
    ports:
      - 8081:80

Then you will be able to connect from a to bridged containers (b, c) through localhost:8080 and localhost:8081

That does the trick thanks @karaxuna!

Just for future reference to anyone Googling this. I ended up doing this specifically:

services:
  a
    network_mode: "host",
    privileged: true
  b
    ports:
      - 127.0.0.1:8080:80
  c
    ports:
      - 127.0.0.1:8081:80

Because I do not want to expose the ports of my internal services to the network my device is connected to.

1 Like