clinuxkernelsocketcan

Linux SocketCAN behaviour of recvmsg


I'm writing a CAN logger program. The way I log the data is similar to the way the candump-tool is doing it when invoking candump like candump any: https://github.com/linux-can/can-utils/blob/master/candump.c

candump any makes candump bind to any device, i.e. addr.can_ifindex = 0; then it uses recvmsg to obtain a CAN frame, then it gets the on the struct msghdr msg; attached timestamp to write it into the log file or onto the screen.

My question here is, does the kernel ensures that the following assert is always valid?

struct msghdr msg;
// init stuff
// ...
s[0] = _skt_1; // can0
s[1] = _skt_2; // can1
// configure and bind sockets
// ...
select(s[1]+1, &rdfs, NULL, NULL, NULL));
recvmsg(s[0], &msg, 0); // https://linux.die.net/man/2/recvmsg
timestamp_1 = getTimestamp(msg);
recvmsg(s[1], &msg, 0); // https://linux.die.net/man/2/recvmsg
timestamp_2 = getTimestamp(msg);
// Always valid?
assert(timestamp_1 < timestamp_2);

A hint to the source code location in the SocketCAN driver would be helpful too.


Solution

  • The short answer is yes, unless your driver does something very weird. CAN uses the same netif subsystem that other network devices use. There are a few ways that the SKB gets a timestamp.

    HW Timestamps:

    If your driver uses hardware time stamps, then time stamps are based on whatever the hardware provides.

    SW Timestamps:

    If netdev_tstamp_prequeue is enabled then a timestamp is soon after your driver submits the skb to netif_receive_skb

    https://elixir.bootlin.com/linux/v4.14.202/source/net/core/dev.c#L4554

    If netdev_tstamp_prequeue is not enabled then the timestamp is applied after a bit more processing but still in the same NAPI receive thread.

    https://elixir.bootlin.com/linux/v4.14.202/source/net/core/dev.c#L4352

    Here is the fuzzy part:

    There are special modes (RSP/RFP) that allow the kernel to load balance skb processing with SMP. Instead of processing the skb in the napi receive thread, the kernel puts the skb in a per cpu queue. Now if netdev_tstamp_prequeue is not enabled, the timestamp is added when it comes off the per cpu queue some time later. However, the documentation says the receive ordering is not modified so time stamps should remain in order as well.