FreeBSD/sys/dev/sfxge/sfxge_rx.c
/* Try to merge or otherwise hold or deliver (as appropriate) the
 * packet buffered for this connection (c->next_buf).  Return a flag
 * indicating whether the connection is still active for LRO purposes.
 */
Try to merge or otherwise hold or deliver (as appropriate) the
packet buffered for this connection (c->next_buf).  Return a flag
indicating whether the connection is still active for LRO purposes.
Try to merge or otherwise hold or deliver ( as appropriate ) the packet buffered for this connection ( c - > next_buf ) . Return a flag indicating whether the connection is still active for LRO purposes .
static int
sfxge_lro_try_merge(struct sfxge_rxq *rxq, struct sfxge_lro_conn *c)
{
	struct sfxge_rx_sw_desc *rx_buf = &c->next_buf;
	char *eh = c->next_eh;
	int data_length, hdr_length, dont_merge;
	unsigned th_seq, pkt_length;
	struct tcphdr *th;
	unsigned now;
	if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) {
		struct ip *iph = c->next_nh;
		th = (struct tcphdr *)(iph + 1);
		pkt_length = ntohs(iph->ip_len) + (char *) iph - eh;
	} else {
		struct ip6_hdr *iph = c->next_nh;
		th = (struct tcphdr *)(iph + 1);
		pkt_length = ntohs(iph->ip6_plen) + (char *) th - eh;
	}
	hdr_length = (char *) th + th->th_off * 4 - eh;
	data_length = (min(pkt_length, rx_buf->size - rxq->sc->rx_prefix_size) -
		       hdr_length);
	th_seq = ntohl(th->th_seq);
	dont_merge = ((data_length <= 0)
		      | (th->th_flags & (TH_URG | TH_SYN | TH_RST | TH_FIN)));
	if (th->th_off != 5) {
		const uint32_t *opt_ptr = (const uint32_t *) (th + 1);
		if (th->th_off == 8 &&
		    opt_ptr[0] == ntohl((TCPOPT_NOP << 24) |
					(TCPOPT_NOP << 16) |
					(TCPOPT_TIMESTAMP << 8) |
					TCPOLEN_TIMESTAMP)) {
		} else {
			dont_merge = 1;
		}
	}
	if (__predict_false(th_seq != c->next_seq)) {
		if (c->mbuf != NULL)
			sfxge_lro_deliver(&rxq->lro, c);
		c->n_in_order_pkts -= lro_loss_packets;
		c->next_seq = th_seq + data_length;
		++rxq->lro.n_misorder;
		goto deliver_buf_out;
	}
	c->next_seq = th_seq + data_length;
	now = ticks;
	if (now - c->last_pkt_ticks > lro_idle_ticks) {
		++rxq->lro.n_drop_idle;
		if (c->mbuf != NULL)
			sfxge_lro_deliver(&rxq->lro, c);
		sfxge_lro_drop(rxq, c);
		return (0);
	}
	c->last_pkt_ticks = ticks;
	if (c->n_in_order_pkts < lro_slow_start_packets) {
		++rxq->lro.n_slow_start;
		++c->n_in_order_pkts;
		goto deliver_buf_out;
	}
	if (__predict_false(dont_merge)) {
		if (c->mbuf != NULL)
			sfxge_lro_deliver(&rxq->lro, c);
		if (th->th_flags & (TH_FIN | TH_RST)) {
			++rxq->lro.n_drop_closed;
			sfxge_lro_drop(rxq, c);
			return (0);
		}
		goto deliver_buf_out;
	}
	rx_buf->mbuf->m_data += rxq->sc->rx_prefix_size;
	if (__predict_true(c->mbuf != NULL)) {
		rx_buf->mbuf->m_data += hdr_length;
		rx_buf->mbuf->m_len = data_length;
		sfxge_lro_merge(&rxq->lro, c, rx_buf->mbuf, th);
	} else {
		rx_buf->mbuf->m_len = pkt_length;
		sfxge_lro_start(&rxq->lro, c, rx_buf->mbuf, c->next_nh, th);
	}
	rx_buf->mbuf = NULL;
	return (1);
 deliver_buf_out:
	sfxge_rx_deliver(rxq->sc, rx_buf);
	return (1);
}
static int sfxge_lro_try_merge ( struct sfxge_rxq * rxq , struct sfxge_lro_conn * c ) { struct sfxge_rx_sw_desc * rx_buf = & c -> next_buf ; char * eh = c -> next_eh ; int data_length , hdr_length , dont_merge ; unsigned th_seq , pkt_length ; struct tcphdr * th ; unsigned now ; if ( SFXGE_LRO_CONN_IS_TCPIPV4 ( c ) ) { struct ip * iph = c -> next_nh ; th = ( struct tcphdr * ) ( iph + 1 ) ; pkt_length = ntohs ( iph -> ip_len ) + ( char * ) iph - eh ; } else { struct ip6_hdr * iph = c -> next_nh ; th = ( struct tcphdr * ) ( iph + 1 ) ; pkt_length = ntohs ( iph -> ip6_plen ) + ( char * ) th - eh ; } hdr_length = ( char * ) th + th -> th_off * 4 - eh ; data_length = ( min ( pkt_length , rx_buf -> size - rxq -> sc -> rx_prefix_size ) - hdr_length ) ; th_seq = ntohl ( th -> th_seq ) ; dont_merge = ( ( data_length <= 0 ) | ( th -> th_flags & ( TH_URG | TH_SYN | TH_RST | TH_FIN ) ) ) ; if ( th -> th_off != 5 ) { const uint32_t * opt_ptr = ( const uint32_t * ) ( th + 1 ) ; if ( th -> th_off == 8 && opt_ptr [ 0 ] == ntohl ( ( TCPOPT_NOP << 24 ) | ( TCPOPT_NOP << 16 ) | ( TCPOPT_TIMESTAMP << 8 ) | TCPOLEN_TIMESTAMP ) ) { } else { dont_merge = 1 ; } } if ( __predict_false ( th_seq != c -> next_seq ) ) { if ( c -> mbuf != NULL ) sfxge_lro_deliver ( & rxq -> lro , c ) ; c -> n_in_order_pkts -= lro_loss_packets ; c -> next_seq = th_seq + data_length ; ++ rxq -> lro . n_misorder ; goto deliver_buf_out ; } c -> next_seq = th_seq + data_length ; now = ticks ; if ( now - c -> last_pkt_ticks > lro_idle_ticks ) { ++ rxq -> lro . n_drop_idle ; if ( c -> mbuf != NULL ) sfxge_lro_deliver ( & rxq -> lro , c ) ; sfxge_lro_drop ( rxq , c ) ; return ( 0 ) ; } c -> last_pkt_ticks = ticks ; if ( c -> n_in_order_pkts < lro_slow_start_packets ) { ++ rxq -> lro . n_slow_start ; ++ c -> n_in_order_pkts ; goto deliver_buf_out ; } if ( __predict_false ( dont_merge ) ) { if ( c -> mbuf != NULL ) sfxge_lro_deliver ( & rxq -> lro , c ) ; if ( th -> th_flags & ( TH_FIN | TH_RST ) ) { ++ rxq -> lro . n_drop_closed ; sfxge_lro_drop ( rxq , c ) ; return ( 0 ) ; } goto deliver_buf_out ; } rx_buf -> mbuf -> m_data += rxq -> sc -> rx_prefix_size ; if ( __predict_true ( c -> mbuf != NULL ) ) { rx_buf -> mbuf -> m_data += hdr_length ; rx_buf -> mbuf -> m_len = data_length ; sfxge_lro_merge ( & rxq -> lro , c , rx_buf -> mbuf , th ) ; } else { rx_buf -> mbuf -> m_len = pkt_length ; sfxge_lro_start ( & rxq -> lro , c , rx_buf -> mbuf , c -> next_nh , th ) ; } rx_buf -> mbuf = NULL ; return ( 1 ) ; deliver_buf_out : sfxge_rx_deliver ( rxq -> sc , rx_buf ) ; return ( 1 ) ; }
Try to merge or otherwise hold or deliver (as appropriate) the
 packet buffered for this connection (c->next_buf).
Try to merge or otherwise hold or deliver ( as appropriate ) the packet buffered for this connection ( c - > next_buf ) .
/* Check for options other than aligned timestamp. */ /* timestamp option -- okay */ /* Out-of-order, so start counting again. */ /* May be in slow-start, so don't merge. */ /* Remove headers and any padding */ /* Remove any padding */