Skip to content

"outbound" matches no packets on a Linux SocketCAN live capture #1474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
infrastation opened this issue Feb 21, 2025 · 6 comments
Open

"outbound" matches no packets on a Linux SocketCAN live capture #1474

infrastation opened this issue Feb 21, 2025 · 6 comments

Comments

@infrastation
Copy link
Member

In the current master branch of libpcap inbound matches both Rx and Tx SocketCAN packets (which seems to be by design) and outbound matches no packets.

Steps to reproduce (hardware)

  1. Wire two SocketCAN USB adapters together.
  2. Plug one adapter into host A (Debian 12, kernel version 6.1.128-1).
  3. Plug another adapter into host B (RaspiOS mod of the above, kernel version 6.6.74-1+rpt1).
  4. On each host run:
    # ip li se dev can0 type can bitrate 500000
    # ip li se dev can0 up
    # cangen -g 1000 can0
    
    This sends synthetic test traffic at 1 packet per second in each direction.
  5. At each host look at the packets using candump and observe the packets going in both directions at the expected rate (the timestamps are delta since the previous packet):
    # candump -x -t d can0
     (000.000000)  can0  RX - -  53C   [8]  A4 A7 FC 19 7B D3 B0 71
     (000.280610)  can0  TX - -  4A1   [4]  31 89 E2 69
     (000.719490)  can0  RX - -  1E5   [6]  3F 6D D2 0A 01 AB
     (000.280745)  can0  TX - -  6A0   [8]  EB 76 EF 45 D2 9F 45 21
     (000.719374)  can0  RX - -  74B   [8]  89 34 6D 6A D0 C1 EF 67
     (000.280634)  can0  TX - -  021   [5]  01 AA F5 45 2D
     (000.719354)  can0  RX - -  380   [0] 
     (000.280744)  can0  TX - -  01C   [5]  3F 7A 5C 22 E3
    
  6. At each host look at the packets using tcpdump and observe similar inter-packet timings:
    # tcpdump -n -i can0 -ttt
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on can0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes
     00:00:00.000000 UNSUPPORTED
    	0x0000:  0000 0041 0600 0000 ebb0 4c1f af90 0000  ...A......L.....
     00:00:00.734333 UNSUPPORTED
    	0x0000:  0000 0459 0200 0000 66c2 0000 0000 0000  ...Y....f.......
     00:00:00.265780 UNSUPPORTED
    	0x0000:  0000 05d4 0800 0000 5748 1200 bd22 c81c  ........WH..."..
     00:00:00.734383 UNSUPPORTED
    	0x0000:  0000 037b 0800 0000 3c55 6606 fabc 547f  ...{....<Uf...T.
     00:00:00.265719 UNSUPPORTED
    	0x0000:  0000 0368 0800 0000 49a4 8307 d61e 7c32  ...h....I.....|2
     00:00:00.734359 UNSUPPORTED
    	0x0000:  0000 044a 0800 0000 963e be25 a072 e17c  ...J.....>.%.r.|
     00:00:00.265743 UNSUPPORTED
    	0x0000:  0000 0737 0800 0000 c060 6b5c 6a86 d609  ...7.....`k\j...
     00:00:00.734320 UNSUPPORTED
    	0x0000:  0000 06d9 0800 0000 8466 3943 36e2 3514  .........f9C6.5.
    
  7. On any host try inbound and observe the same:
    # timeout 4 tcpdump -n -i can0 -ttt inbound
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on can0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes
     00:00:00.000000 UNSUPPORTED
    	0x0000:  0000 0149 0100 0000 2700 0000 0000 0000  ...I....'.......
     00:00:00.716940 UNSUPPORTED
    	0x0000:  0000 048f 0800 0000 023e b533 81e7 a374  .........>.3...t
     00:00:00.283203 UNSUPPORTED
    	0x0000:  0000 02bc 0300 0000 4f72 5400 0000 0000  ........OrT.....
     00:00:00.716936 UNSUPPORTED
    	0x0000:  0000 03e0 0800 0000 4bde d23c 7f03 0c30  ........K..<...0
     00:00:00.283239 UNSUPPORTED
    	0x0000:  0000 04ec 0800 0000 d110 b303 4b2e 174a  ............K..J
     00:00:00.716803 UNSUPPORTED
    	0x0000:  0000 046e 0800 0000 aff4 d519 56d5 937d  ...n........V..}
     00:00:00.283255 UNSUPPORTED
    	0x0000:  0000 0165 0500 0000 77a9 6635 2e00 0000  ...e....w.f5....
    
    7 packets captured
    8 packets received by filter
    0 packets dropped by kernel
    
  8. On any host try outbound and observe no packets:
    # timeout 10 tcpdump -n -i can0 -ttt outbound 
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on can0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes
    
    0 packets captured
    10 packets received by filter
    0 packets dropped by kernel
    

Steps to reproduce (virtual device)

# ip li add type vcan
# ip li se dev vcan0 up
# cangen -g 1000 vcan0

(in a different terminal)
# timeout 3 candump -x -t d vcan0
 (000.000000)  vcan0  TX - -  610   [8]  52 41 3A 22 51 56 3D 4D
 (001.000068)  vcan0  TX - -  69A   [8]  BF 44 CA 00 F8 A0 4E 56
 (001.000064)  vcan0  TX - -  29D   [0] 

# timeout 3 tcpdump -n -i vcan0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vcan0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes
 00:00:00.000000 UNSUPPORTED
	0x0000:  0000 03b2 0800 0000 dc9f 2b64 fa6d e43f  ..........+d.m.?
 00:00:01.000071 UNSUPPORTED
	0x0000:  0000 02de 0800 0000 cce7 8c4b 0bd9 1f75  ...........K...u
 00:00:01.000064 UNSUPPORTED
	0x0000:  0000 003c 0800 0000 2986 7b37 454b f768  ...<....).{7EK.h

3 packets captured
6 packets received by filter
0 packets dropped by kernel

# timeout 3 tcpdump -n -i vcan0 -ttt inbound
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vcan0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes
 00:00:00.000000 UNSUPPORTED
	0x0000:  0000 0555 0100 0000 ca00 0000 0000 0000  ...U............
 00:00:01.000066 UNSUPPORTED
	0x0000:  0000 01ee 0800 0000 12b2 9926 6d0d 0213  ...........&m...

2 packets captured
3 packets received by filter
0 packets dropped by kernel

# timeout 3 tcpdump -n -i vcan0 -ttt outbound
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vcan0, link-type CAN_SOCKETCAN (CAN-bus with SocketCAN headers), snapshot length 262144 bytes

0 packets captured
3 packets received by filter
0 packets dropped by kernel
@guyharris
Copy link
Member

Oy.

To fix #1051 "Duplicated CAN packages", apparently caused by CAN adapters or drivers looping back transmitted packets in such a way that they're delivered to the CAN stack as output and to the CAN stack as input, libpcap discards outgoing CAN packet under the assumption that they'll be seen as input.

This means that libpcap will discard outgoing packets, so any packets that pass the filter "outbound" will be discarded.

If there were a reliable way to discover input packets that correspond to packets sent by the machine, we could, instead, discard incoming packets that might already have been seen as outgoing packets, making CAN interfaces look more like, for example, Ethernet interfaces.

(Or if there's a way to cause a PF_PACKET socket that's either 1) bound to a CAN interface or 2) unbound (as in the "any" device) not to see those looped-back outgoing packets, that'd also work.)

@infrastation
Copy link
Member Author

As far as I managed to grasp from the Linux kernel document, the Tx loopback is by design and if the driver does not loop the packets back, the stack will do it anyway. candump seems to handle this transparently (see above) by distinguishing Tx and Rx frames via msg.msg_flags & MSG_DONTROUTE for both short and long frames.

@guyharris
Copy link
Member

From a quick look at https://github.com/linux-can/can-utils/blob/master/candump.c, it only uses that flag to mark frames as "transmitted" or "received", not to discard the received copy of a frame transmitted by the host running candump.

@guyharris
Copy link
Member

The Documentation/networking/can.rst file says

Local Loopback of Sent Frames
-----------------------------

As known from other networking concepts the data exchanging
applications may run on the same or different nodes without any
change (except for the according addressing information):

.. code::

         ___   ___   ___                   _______   ___
        | _ | | _ | | _ |                 | _   _ | | _ |
        ||A|| ||B|| ||C||                 ||A| |B|| ||C||
        |___| |___| |___|                 |_______| |___|
          |     |     |                       |       |
        -----------------(1)- CAN bus -(2)---------------

To ensure that application A receives the same information in the 
example (2) as it would receive in example (1) there is need for 
some kind of local loopback of the sent CAN frames on the appropriate
node.

The Linux network devices (by default) just can handle the
transmission and reception of media dependent frames. Due to the     
arbitration on the CAN bus the transmission of a low prio CAN-ID
may be delayed by the reception of a high prio CAN frame. To
reflect the correct [#f1]_ traffic on the node the loopback of the sent
data has to be performed right after a successful transmission. If
the CAN network interface is not capable of performing the loopback for
some reason the SocketCAN core can do this task as a fallback solution.
See :ref:`socketcan-local-loopback2` for details (recommended).

The loopback functionality is enabled by default to reflect standard
networking behaviour for CAN applications.  Due to some requests from
the RT-SocketCAN group the loopback optionally may be disabled for each
separate socket.  See sockopts from the CAN RAW sockets in
:ref:`socketcan-raw-sockets`.

.. [#f1] you really like to have this when you're running analyser
       tools like 'candump' or 'cansniffer' on the (same) node.

The problem is that tcpdump/Wireshark/etc. is, in that scenario, like an application D that, if running on the first machine in example (1), would want to see all packets transmitted by application A and all packets received by that host from the other machines and, if running on the first machine in example (2), would want to see all packets transmitted by application A and B and all packets received by that host from the other machines - and not see two copies of packets sent by applications on the same machine. This is a bit different from what the section of the document in question says.

@infrastation
Copy link
Member Author

It could be one of the many setsockopt() calls as well, but the end result is that somehow it manages to see the correct numbers of Tx and Rx frames on a host that is both receiving and transmitting (see above).

@guyharris
Copy link
Member

So if there's a way to specify for a particular PF_PACKET socket that, for frames of any sort transmitted by the machine on which the program using that socket is running, any looped-back versions of those frames are not seen, so only the transmitted versions are seen, that's what we'd want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants