Getting CAN interface packet statistics using getifaddrs

Viewed 242

I'm using the getifaddrs Linux function to get information about network interfaces on a Linux machine running Debian Jessie kernel 3.16.0.

Among the info I want to know is network statistics (packets dropped, sent, etc.) which, as the manpage for getifaddrs states, is contained in a rtnl_link_stats structure pointed to by ifaddrs::ifa_addr::ifa_data when ifaddrs::if_addr::sa_family is set to AF_PACKET.

This works well for ethernet interfaces, but does not work for CAN interfaces on the machine, because ifaddrs::ifa_addr is NULL and thus AF_PACKET is never returned for any CAN interface.

The following C++ code...

#include <ifaddrs.h>
#include <linux/if_link.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <cstdio>
#include <cstdlib>

int main() {
  ifaddrs *addrs;
  if (getifaddrs(&addrs) == -1) {
    perror("getifaddrs");
    return EXIT_FAILURE;
  }

  printf("AF_PACKET: %d\n\n", (int)AF_PACKET);

  for (auto addr = addrs; addr != NULL; addr = addr->ifa_next) {
    if (addr->ifa_addr != nullptr) {
      printf("%s: family: %d\n", addr->ifa_name, (int)addr->ifa_addr->sa_family);
    } else {
      printf("%s: family: none\n", addr->ifa_name);
    }
  }

  freeifaddrs(addrs);

  return EXIT_SUCCESS;
}

...prints out

AF_PACKET: 17

lo: family: 17
eth0: family: 17
eth1: family: 17
can0: family: none
can1: family: none
lo: family: 2
eth1: family: 2
lo: family: 10
eth1: family: 10

which means that neither of the CAN interfaces have any family set.

The ifconfig command has no problem showing the information, though:

can0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          UP RUNNING NOARP  MTU:16  Metric:1
          RX packets:28481588 errors:0 dropped:8729866 overruns:0 frame:0
          TX packets:8168599 errors:2292404 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:10 
          RX bytes:211108099 (201.3 MiB)  TX bytes:64828340 (61.8 MiB)
          Interrupt:17 

can1      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          UP RUNNING 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)
          Interrupt:17

(note I included only the output for CAN interfaces, not the rest)

What am I doing wrong? What is the correct way to retrieve packet stats for CAN interfaces?

3 Answers

Use the "address_family" option in the "ifconfig" command; check your "man ifconfig" page, here is the relevant text from mine (no CAN intfs on my system):

...
     address_family
             Specify the address family which affects interpretation of the remaining parameters.  Since an interface
             can receive transmissions in differing protocols with different naming schemes, specifying the address
             family is recommended.  The address or protocol families currently supported are ``inet'', ``inet6'', and
             ``link''.  The default is ``inet''.  ``ether'' and ``lladdr'' are synonyms for ``link''.

Given net-tools source code it reads file /proc/net/dev in the proc filesystem for this information.

See the following functions in lib/interface.c:

  • if_readlist()

  • if_readlist_proc()

Good luck with your project!

EDIT> With a CAN adapter connected

File /proc/net/dev:

Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
slcan0:       0       0    0    0    0     0          0         0      344      43    0    0    0     0       0          0

Output of ifconfig:

slcan0: flags=193<UP,RUNNING,NOARP>  mtu 16
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 43  bytes 344 (344.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

I had a similar problem in my C project nagios-plugins-linux and had to switch from the very easy interface getifaddrs to linux rtnetlink, which is a lot more complex to manage but also more powerfull (getifaddrs provides the network statistics for the AF_PACKET family only, if I remember correctly).

You can find the related code in the library files:

I'm not able to check a can0 interface but my code detects a vcan0 one and should anyway work for any network interface.

Related