void ci_sock_cmn_timestamp_q_enqueue(ci_netif* ni, ci_sock_cmn* s, ci_ip_pkt_fmt* pkt) { ci_ip_pkt_queue* qu = &s->timestamp_q; oo_pkt_p prev_head = qu->head; /* This part is effectively ci_ip_queue_enqueue(ni, &s->timestamp_q, p); * but inlined to allow using tsq_next field */ pkt->tsq_next = OO_PP_NULL; if( ci_ip_queue_is_empty(qu) ) { ci_assert(OO_PP_IS_NULL(qu->head)); qu->head = OO_PKT_P(pkt); } else { ci_assert(OO_PP_NOT_NULL(qu->head)); /* This assumes the netif lock is held, so use ci_ip_queue_enqueue_nnl() if it's not */ PKT(ni, qu->tail)->tsq_next = OO_PKT_P(pkt); } qu->tail = OO_PKT_P(pkt); qu->num++; if( OO_PP_IS_NULL(prev_head) ) { ci_assert(OO_PP_IS_NULL(s->timestamp_q_extract)); s->timestamp_q_extract = qu->head; } else { ci_sock_cmn_timestamp_q_reap(ni, s); } /* Tells post-poll loop to put socket on the [reap_list]. */ s->b.sb_flags |= CI_SB_FLAG_RX_DELIVERED; }
int ci_ip_send_pkt_send(ci_netif* ni, ci_ip_pkt_fmt* pkt, const ci_ip_cached_hdrs* ipcache) { int os_rc = 0; switch( ipcache->status ) { case retrrc_success: ci_ip_set_mac_and_port(ni, ipcache, pkt); ci_netif_send(ni, pkt); return 0; case retrrc_nomac: cicp_user_defer_send(ni, retrrc_nomac, &os_rc, OO_PKT_P(pkt), ipcache->ifindex); return 0; case retrrc_noroute: return -EHOSTUNREACH; case retrrc_alienroute: return -ENETUNREACH; case retrrc_localroute: if( ipcache->flags & CI_IP_CACHE_IS_LOCALROUTE ) ci_assert(0); /*passthrough*/ default: if( ipcache->status < 0 ) return ipcache->status; else /* belt and braces... */ return 0; } }
/** * 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); }
void ci_ip_send_tcp_slow(ci_netif* ni, ci_tcp_state* ts, ci_ip_pkt_fmt* pkt) { /* We're here because the ipcache is not valid. */ int rc, prev_mtu = ts->s.pkt.mtu; cicp_user_retrieve(ni, &ts->s.pkt, &ts->s.cp); if( ts->s.pkt.status == retrrc_success ) { if( ts->s.pkt.mtu != prev_mtu ) CI_PMTU_TIMER_NOW(ni, &ts->pmtus); ci_ip_set_mac_and_port(ni, &ts->s.pkt, pkt); ci_netif_send(ni, pkt); return; } else if( ts->s.pkt.status == retrrc_localroute && (ts->s.pkt.flags & CI_IP_CACHE_IS_LOCALROUTE) ) ci_ip_local_send(ni, pkt, &ts->s, OO_SP_NULL); /* For TCP, we want the ipcache to only be valid when onloadable. */ ci_ip_cache_invalidate(&ts->s.pkt); switch( ts->s.pkt.status ) { case retrrc_nomac: rc = 0; /* If we resend SYN, and there is no MAC - it means ARP failed. * Connect() should return with EHOSTUNREACH. * We verify twice - on the first and the second retransmit. * Very hackish. */ if( ts->s.b.state == CI_TCP_SYN_SENT ) { if( ts->retransmits == 1 ) ts->tcpflags |= CI_TCPT_FLAG_NO_ARP; else if( (ts->tcpflags & CI_TCPT_FLAG_NO_ARP) && ts->retransmits == 2 ) { ci_tcp_drop(ni, ts, EHOSTUNREACH); return; } } cicp_user_defer_send(ni, retrrc_nomac, &rc, OO_PKT_P(pkt), ts->s.pkt.ifindex); ++ts->stats.tx_nomac_defer; return; case retrrc_noroute: rc = -EHOSTUNREACH; break; case retrrc_alienroute: case retrrc_localroute: /* ?? TODO: inc some stat */ return; default: ci_assert_lt(ts->s.pkt.status, 0); if( ts->s.pkt.status < 0 ) rc = ts->s.pkt.status; else /* belt and braces... */ rc = 0; } ci_assert_le(rc, 0); /* In most cases, we should ignore return code; the packet will be resend * later, because of RTO. However, in SYN-SENT we should pass errors to * user. At the same time, we should not pass ENOBUFS to user - it is * pretty internal problem of cplane, so we should try again. Possibly, * there may be other internal problems, such as ENOMEM. * * Also, do not break connection when the first SYN fails: * - Linux does not do it; * - cplane has some latency, so we have false positives here; * - ci_tcp_connect() does not expect it. */ if( ts->s.b.state == CI_TCP_SYN_SENT && rc < 0 && ts->retransmits > 0 && (rc == -EHOSTUNREACH || rc == -ENETUNREACH || rc == -ENETDOWN) ) ci_tcp_drop(ni, ts, -rc); }