0

I'm receiving packets via recvmsg() and expecting 3 timestamps:

  1. Software
  2. Hardware (NIC) converted to software
  3. Hardware (NIC)

I see the first and third timestamps but I get zeros for the second.

I'm basing my code on this Onload example:

https://github.com/Xilinx-CNS/onload/blob/master/src/tests/onload/hwtimestamping/rx_timestamping.c

I export the environment variable for timestamping:

export EF_RX_TIMESTAMPING=1

I preload the onload library.

I set the socket options:

int enable = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE |
                 SOF_TIMESTAMPING_SYS_HARDWARE | SOF_TIMESTAMPING_SOFTWARE;
assert(setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &enable, sizeof(int)) == 0);

I create the message header and use recvmsg() to retrieve packets:

  while(_running)
  {
      struct iovec iov;
      char control[1024];
      struct msghdr msg;

      iov.iov_base = buffer;
      iov.iov_len = 2048;
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      msg.msg_namelen = sizeof(struct sockaddr_in);
      msg.msg_control = control;
      msg.msg_controllen = 1024;

      int num bytes = recvmsg(sock, &msg, 0);
      handle_time(&msg);
      LOG("Got packet");
  }

and I read the timestamps:

static void handle_time(struct msghdr* msg)
{
  struct timespec* ts = NULL;
  struct cmsghdr* cmsg;

  for( cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg,cmsg) ) {
    if( cmsg->cmsg_level != SOL_SOCKET )
      continue;

    switch( cmsg->cmsg_type ) {
    case SO_TIMESTAMPNS:
      ts = (struct timespec*) CMSG_DATA(cmsg);
      break;
    case SO_TIMESTAMPING:
      ts = (struct timespec*) CMSG_DATA(cmsg);
      break;
    default:
      /* Ignore other cmsg options */
      break;
    }
  }

  print_time(ts);
}

static void print_time(struct timespec* ts)
{
  if( ts != NULL ) {
    /* Hardware timestamping provides three timestamps -
     *   system (software)
     *   transformed (hw converted to sw)
     *   raw (hardware)
     * in that order - though depending on socket option, you may have 0 in
     * some of them.
     */
    printf("timestamps " TIME_FMT TIME_FMT TIME_FMT "\n",
      (uint64_t)ts[0].tv_sec, (uint64_t)ts[0].tv_nsec,
      (uint64_t)ts[1].tv_sec, (uint64_t)ts[1].tv_nsec,
      (uint64_t)ts[2].tv_sec, (uint64_t)ts[2].tv_nsec );
  } else
  {
    printf( "no timestamp\n" );
  }
}

Is there anything missing to receive the second timestamp?

kaylum
  • 13,833
  • 2
  • 22
  • 31
user997112
  • 29,025
  • 43
  • 182
  • 361

1 Answers1

0

It's probably the network interface driver that needs to add the timestamp from the hardware. What kind of hardware are we talking about? Can you show some ethanol output?

Cheatah
  • 1,825
  • 2
  • 13
  • 21
  • It's a Solarflare adaptor. When we run `ethtool -T` on the interface it lists all four of the flags under the capabilities. – user997112 Aug 05 '21 at 12:57