コード例 #1
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put a SO_TIMESTAMPING control message into msg ancillary data buffer.
 */
void ip_cmsg_recv_timestamping(ci_netif *ni,
      ci_uint64 sys_timestamp, struct timespec* hw_timestamp,
      int flags, struct cmsg_state *cmsg_state)
{
  struct {
    struct timespec systime;
    struct timespec hwtimetrans;
    struct timespec hwtimeraw;
  } ts;

  int c_flags = 0;

  if( hw_timestamp->tv_sec != 0 )
    c_flags = flags & (ONLOAD_SOF_TIMESTAMPING_RAW_HARDWARE
                      | ONLOAD_SOF_TIMESTAMPING_SYS_HARDWARE);
  if( sys_timestamp != 0 )
    c_flags |= flags & ONLOAD_SOF_TIMESTAMPING_SOFTWARE;

  memset(&ts, 0, sizeof(ts));
  if( c_flags & ONLOAD_SOF_TIMESTAMPING_SOFTWARE )
    ci_udp_compute_stamp(ni, sys_timestamp, &ts.systime);
  if( c_flags & ONLOAD_SOF_TIMESTAMPING_RAW_HARDWARE )
    ts.hwtimeraw = *hw_timestamp;
  if( c_flags & ONLOAD_SOF_TIMESTAMPING_SYS_HARDWARE )
    ts.hwtimetrans = *hw_timestamp;

  ci_put_cmsg(cmsg_state, SOL_SOCKET, ONLOAD_SO_TIMESTAMPING, sizeof(ts), &ts);
}
コード例 #2
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put an IP_RECVTOS control message into msg ancillary data buffer.
 */
ci_inline void ip_cmsg_recv_tos(const ci_ip_pkt_fmt *pkt, 
                                struct cmsg_state *cmsg_state)
{
  int tos = oo_ip_hdr_const(pkt)->ip_tos;

  ci_put_cmsg(cmsg_state, IPPROTO_IP, IP_TOS, sizeof(tos), &tos);
}
コード例 #3
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put an IP_RECVTTL control message into msg ancillary data buffer.
 */
ci_inline void ip_cmsg_recv_ttl(const ci_ip_pkt_fmt *pkt, 
                                struct cmsg_state *cmsg_state)
{
  int ttl = oo_ip_hdr_const(pkt)->ip_ttl;

  ci_put_cmsg(cmsg_state, IPPROTO_IP, IP_TTL, sizeof(ttl), &ttl);
}
コード例 #4
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put a SO_TIMESTAMPNS control message into msg ancillary data buffer.
 */
void ip_cmsg_recv_timestampns(ci_netif *ni, ci_uint64 timestamp, 
                                        struct cmsg_state *cmsg_state)
{
  struct timespec ts;

  ci_udp_compute_stamp(ni, timestamp, &ts);

  ci_put_cmsg(cmsg_state, SOL_SOCKET, SO_TIMESTAMPNS, sizeof(ts), &ts);
}
コード例 #5
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put a SO_TIMESTAMP control message into msg ancillary data buffer.
 */
void ip_cmsg_recv_timestamp(ci_netif *ni, ci_uint64 timestamp, 
                                      struct cmsg_state *cmsg_state)
{
  struct timespec ts;
  struct timeval tv;

  ci_udp_compute_stamp(ni, timestamp, &ts);
  tv.tv_sec = ts.tv_sec;
  tv.tv_usec = ts.tv_nsec / 1000;

  ci_put_cmsg(cmsg_state, SOL_SOCKET, SO_TIMESTAMP, sizeof(tv), &tv);
}
コード例 #6
0
ファイル: ip_cmsg.c プロジェクト: arnetheduck/openonload
/**
 * Put an IP_PKTINFO control message into msg ancillary data buffer.
 */
static void ip_cmsg_recv_pktinfo(ci_netif* netif, const ci_ip_pkt_fmt* pkt,
                                 struct cmsg_state *cmsg_state)
{
  /* TODO: This is horribly inefficient -- two system calls.  Could be made
   * cheap with a user-level llap table.
   */
  struct in_pktinfo info;
  ci_uint32 addr;
  int hwport;

  addr = oo_ip_hdr_const(pkt)->ip_daddr_be32;
  info.ipi_addr.s_addr = addr;

  /* Set the ifindex the pkt was received at. */
  {
    ci_ifid_t ifindex = 0;
    int rc = 0;

    hwport = netif->state->intf_i_to_hwport[pkt->intf_i];
    rc = cicp_llap_find(CICP_HANDLE(netif), &ifindex,
                        CI_HWPORT_ID(hwport), pkt->vlan);
    if( rc != 0 )
      LOG_E(ci_log("%s: cicp_llap_find(intf_i=%d, hwport=%d) failed rc=%d",
                   __FUNCTION__, pkt->intf_i, hwport, rc));
    info.ipi_ifindex = ifindex;
  }

  /* RFC1122: The specific-destination address is defined to be the
   * destination address in the IP header unless the header contains a
   * broadcast or multicast address, in which case the specific-destination
   * is an IP address assigned to the physical interface on which the
   * datagram arrived. */
  /*\ FIXME: we should drop the packet if this call fails */
  cicp_ipif_pktinfo_query(CICP_HANDLE(netif), netif, OO_PKT_P(pkt),
                          info.ipi_ifindex, 
                          &info.ipi_spec_dst.s_addr
                          );

  ci_put_cmsg(cmsg_state, IPPROTO_IP, IP_PKTINFO, sizeof(info), &info);
}
コード例 #7
0
ファイル: udp_recv.c プロジェクト: davenso/openonload
static int ci_udp_recvmsg_socklocked_slowpath(ci_udp_iomsg_args* a, 
                                              ci_msghdr* msg,
                                              ci_iovec_ptr *piov, int flags)
{
  int rc = 0;
  ci_netif* ni = a->ni;
  ci_udp_state* us = a->us;

  if(CI_UNLIKELY( ni->state->rxq_low ))
    ci_netif_rxq_low_on_recv(ni, &us->s,
                             1 /* assume at least one pkt freed */);
  /* In the kernel recv() with flags is not called.
   * only read(). So flags may only contain MSG_DONTWAIT */
#ifdef __KERNEL__
  ci_assert_equal(flags, 0);
#endif

#ifndef __KERNEL__
  if( flags & MSG_ERRQUEUE_CHK ) {
    if( OO_PP_NOT_NULL(us->timestamp_q.extract) ) {
      ci_ip_pkt_fmt* pkt;
      struct timespec ts[3];
      struct cmsg_state cmsg_state;
      ci_udp_hdr* udp;
      int paylen;

      /* TODO is this necessary? - mirroring ci_udp_recvmsg_get() */
      ci_rmb();
      
      pkt = PKT_CHK_NNL(ni, us->timestamp_q.extract);
      if( pkt->tx_hw_stamp.tv_sec == CI_PKT_TX_HW_STAMP_CONSUMED ) {
        if( OO_PP_IS_NULL(pkt->tsq_next) )
          goto errqueue_empty;
        us->timestamp_q.extract = pkt->tsq_next;
        pkt = PKT_CHK_NNL(ni, us->timestamp_q.extract);
        ci_assert(pkt->tx_hw_stamp.tv_sec != CI_PKT_TX_HW_STAMP_CONSUMED);
      }

      udp = oo_ip_data(pkt);
      paylen = CI_BSWAP_BE16(oo_ip_hdr(pkt)->ip_tot_len_be16) -
                        sizeof(ci_ip4_hdr) - sizeof(udp);

      msg->msg_flags = 0;
      cmsg_state.msg = msg;
      cmsg_state.cm = msg->msg_control;
      cmsg_state.cmsg_bytes_used = 0;
      ci_iovec_ptr_init_nz(piov, msg->msg_iov, msg->msg_iovlen);
      memset(ts, 0, sizeof(ts));

      if( us->s.timestamping_flags & ONLOAD_SOF_TIMESTAMPING_RAW_HARDWARE ) {
        ts[2].tv_sec = pkt->tx_hw_stamp.tv_sec;
        ts[2].tv_nsec = pkt->tx_hw_stamp.tv_nsec;
      }
      if( (us->s.timestamping_flags & ONLOAD_SOF_TIMESTAMPING_SYS_HARDWARE) &&
          (pkt->tx_hw_stamp.tv_nsec & CI_IP_PKT_HW_STAMP_FLAG_IN_SYNC) ) {
        ts[1].tv_sec = pkt->tx_hw_stamp.tv_sec;
        ts[1].tv_nsec = pkt->tx_hw_stamp.tv_nsec;
      }
      ci_put_cmsg(&cmsg_state, SOL_SOCKET, ONLOAD_SCM_TIMESTAMPING,
                  sizeof(ts), &ts);
      oo_offbuf_set_start(&pkt->buf, udp + 1);
      oo_offbuf_set_len(&pkt->buf, paylen);
      rc = oo_copy_pkt_to_iovec_no_adv(ni, pkt, piov, paylen);

      /* Mark this packet/timestamp as consumed */
      pkt->tx_hw_stamp.tv_sec = CI_PKT_TX_HW_STAMP_CONSUMED;

      ci_ip_cmsg_finish(&cmsg_state);
      msg->msg_flags |= MSG_ERRQUEUE_CHK;
      return rc;
    }
  errqueue_empty:
    /* ICMP is handled via OS, so get OS error */
    rc = oo_os_sock_recvmsg(ni, SC_SP(&us->s), msg, flags);
    if( rc < 0 ) {
      ci_assert(-rc == errno);
      return -1;
    }
    else
      return rc;
  }
#endif
  if( (rc = ci_get_so_error(&us->s)) != 0 ) {
    CI_SET_ERROR(rc, rc);
    return rc;
  }
  if( msg->msg_iovlen > 0 && msg->msg_iov == NULL ) {
    CI_SET_ERROR(rc, EFAULT);
    return rc;
  }
#if MSG_OOB_CHK
  if( flags & MSG_OOB_CHK ) {
    CI_SET_ERROR(rc, EOPNOTSUPP);
    return rc;
  }
#endif
#if CI_CFG_POSIX_RECV  
  if( ! udp_lport_be16(us)) {
    LOG_UV(log("%s: -1 (ENOTCONN)", __FUNCTION__));
    CI_SET_ERROR(rc, ENOTCONN);
    return rc;
  }
#endif
  if( msg->msg_iovlen == 0 ) {
    /* We have a difference in behaviour from the Linux stack here.  When
    ** msg_iovlen is 0 Linux 2.4.21-15.EL does not set MSG_TRUNC when a
    ** datagram has non-zero length.  We do. */
    CI_IOVEC_LEN(&piov->io) = piov->iovlen = 0;
    return IOVLEN_WORKAROUND_RC_VALUE;
  }
  return 0;
}