FreeBSD/sys/netinet/khelp/h_ertt.c
/*
 * Ertt_packet_measurements uses a small amount of state kept on each packet
 * sent to match incoming acknowledgements. This enables more accurate and
 * secure round trip time measurements. The resulting measurement is used for
 * congestion control algorithms which require a more accurate time.
 * Ertt_packet_measurements is called via the helper hook in tcp_input.c
 */
Ertt_packet_measurements uses a small amount of state kept on each packet
sent to match incoming acknowledgements. This enables more accurate and
secure round trip time measurements. The resulting measurement is used for
congestion control algorithms which require a more accurate time.
Ertt_packet_measurements is called via the helper hook in tcp_input.c
Ertt_packet_measurements uses a small amount of state kept on each packet sent to match incoming acknowledgements . This enables more accurate and secure round trip time measurements . The resulting measurement is used for congestion control algorithms which require a more accurate time . Ertt_packet_measurements is called via the helper hook in tcp_input . c
static int
ertt_packet_measurement_hook(int hhook_type, int hhook_id, void *udata,
    void *ctx_data, void *hdata, struct osd *hosd)
{
	struct ertt *e_t;
	struct tcpcb *tp;
	struct tcphdr *th;
	struct tcpopt *to;
	struct tcp_hhook_data *thdp;
	struct txseginfo *txsi;
	int acked, measurenext_len, multiack, new_sacked_bytes, rtt_bytes_adjust;
	uint32_t measurenext, rts;
	tcp_seq ack;
	KASSERT(ctx_data != NULL, ("%s: ctx_data is NULL!", __func__));
	KASSERT(hdata != NULL, ("%s: hdata is NULL!", __func__));
	e_t = (struct ertt *)hdata;
	thdp = ctx_data;
	tp = thdp->tp;
	th = thdp->th;
	to = thdp->to;
	new_sacked_bytes = (tp->sackhint.last_sack_ack != 0);
	measurenext = measurenext_len = multiack = rts = rtt_bytes_adjust = 0;
	acked = th->th_ack - tp->snd_una;
	INP_WLOCK_ASSERT(tp->t_inpcb);
	if (acked > 0 || new_sacked_bytes) {
		if (acked == 0 && new_sacked_bytes) {
			ack = tp->sackhint.last_sack_ack;
		} else
			ack = th->th_ack;
		txsi = TAILQ_FIRST(&e_t->txsegi_q);
		while (txsi != NULL) {
			rts = 0;
			if (SEQ_GT(ack, txsi->seq + txsi->len)) {
				if (txsi->flags & TXSI_RTT_MEASURE_START ||
				    measurenext) {
					marked_packet_rtt(txsi, e_t, tp,
					    &measurenext, &measurenext_len,
					    &rtt_bytes_adjust, MULTI_ACK);
				}
				TAILQ_REMOVE(&e_t->txsegi_q, txsi, txsegi_lnk);
				uma_zfree(txseginfo_zone, txsi);
				txsi = TAILQ_FIRST(&e_t->txsegi_q);
				continue;
			}
			if (!new_sacked_bytes) {
				if (acked > tp->t_maxseg) {
					e_t->dlyack_rx +=
					    (e_t->dlyack_rx < DLYACK_SMOOTH) ?
					    1 : 0;
					multiack = 1;
				} else if (acked > txsi->len) {
					multiack = 1;
					e_t->dlyack_rx +=
					    (e_t->dlyack_rx < DLYACK_SMOOTH) ?
					    1 : 0;
				} else if (acked == tp->t_maxseg ||
					   acked == txsi->len) {
					e_t->dlyack_rx -=
					    (e_t->dlyack_rx > 0) ? 1 : 0;
				}
			}
			if (e_t->timestamp_errors < MAX_TS_ERR &&
			    (to->to_flags & TOF_TS) != 0 && to->to_tsecr) {
				rts = to->to_tsecr;
				if (!e_t->dlyack_rx && TSTMP_LT(rts, txsi->tx_ts))
					break;
				if (TSTMP_GT(rts, txsi->tx_ts)) {
					if (txsi->flags & TXSI_RTT_MEASURE_START
					    || measurenext) {
						marked_packet_rtt(txsi, e_t, tp,
						    &measurenext, &measurenext_len,
						    &rtt_bytes_adjust, OLD_TXSI);
					}
					TAILQ_REMOVE(&e_t->txsegi_q, txsi,
					    txsegi_lnk);
					uma_zfree(txseginfo_zone, txsi);
					txsi = TAILQ_FIRST(&e_t->txsegi_q);
					continue;
				}
				if (rts == txsi->tx_ts &&
				    TSTMP_LT(to->to_tsval, txsi->rx_ts)) {
					e_t->timestamp_errors++;
				}
			}
			if (SEQ_LEQ(ack, txsi->seq))
				break; 
			if (!e_t->dlyack_rx || multiack || new_sacked_bytes) {
				e_t->rtt = tcp_ts_getticks() - txsi->tx_ts + 1;
				if (e_t->rtt < e_t->minrtt || e_t->minrtt == 0)
					e_t->minrtt = e_t->rtt;
				if (e_t->rtt > e_t->maxrtt || e_t->maxrtt == 0)
					e_t->maxrtt = e_t->rtt;
			}
			if (txsi->flags & TXSI_RTT_MEASURE_START || measurenext)
				marked_packet_rtt(txsi, e_t, tp,
				    &measurenext, &measurenext_len,
				    &rtt_bytes_adjust, CORRECT_ACK);
			if (txsi->flags & TXSI_TSO) {
				txsi->len -= acked;
				if (txsi->len > 0) {
					txsi->seq += acked;
					txsi->flags &= ~TXSI_RTT_MEASURE_START;
					break;
				}
			}
			TAILQ_REMOVE(&e_t->txsegi_q, txsi, txsegi_lnk);
			uma_zfree(txseginfo_zone, txsi);
			break;
		}
		if (measurenext) {
			marked_packet_rtt(txsi, e_t, tp,
			    &measurenext, &measurenext_len,
			    &rtt_bytes_adjust, FORCED_MEASUREMENT);
		}
	}
	return (0);
}
static int ertt_packet_measurement_hook ( int hhook_type , int hhook_id , void * udata , void * ctx_data , void * hdata , struct osd * hosd ) { struct ertt * e_t ; struct tcpcb * tp ; struct tcphdr * th ; struct tcpopt * to ; struct tcp_hhook_data * thdp ; struct txseginfo * txsi ; int acked , measurenext_len , multiack , new_sacked_bytes , rtt_bytes_adjust ; uint32_t measurenext , rts ; tcp_seq ack ; KASSERT ( ctx_data != NULL , ( " " , __func__ ) ) ; KASSERT ( hdata != NULL , ( " " , __func__ ) ) ; e_t = ( struct ertt * ) hdata ; thdp = ctx_data ; tp = thdp -> tp ; th = thdp -> th ; to = thdp -> to ; new_sacked_bytes = ( tp -> sackhint . last_sack_ack != 0 ) ; measurenext = measurenext_len = multiack = rts = rtt_bytes_adjust = 0 ; acked = th -> th_ack - tp -> snd_una ; INP_WLOCK_ASSERT ( tp -> t_inpcb ) ; if ( acked > 0 || new_sacked_bytes ) { if ( acked == 0 && new_sacked_bytes ) { ack = tp -> sackhint . last_sack_ack ; } else ack = th -> th_ack ; txsi = TAILQ_FIRST ( & e_t -> txsegi_q ) ; while ( txsi != NULL ) { rts = 0 ; if ( SEQ_GT ( ack , txsi -> seq + txsi -> len ) ) { if ( txsi -> flags & TXSI_RTT_MEASURE_START || measurenext ) { marked_packet_rtt ( txsi , e_t , tp , & measurenext , & measurenext_len , & rtt_bytes_adjust , MULTI_ACK ) ; } TAILQ_REMOVE ( & e_t -> txsegi_q , txsi , txsegi_lnk ) ; uma_zfree ( txseginfo_zone , txsi ) ; txsi = TAILQ_FIRST ( & e_t -> txsegi_q ) ; continue ; } if ( ! new_sacked_bytes ) { if ( acked > tp -> t_maxseg ) { e_t -> dlyack_rx += ( e_t -> dlyack_rx < DLYACK_SMOOTH ) ? 1 : 0 ; multiack = 1 ; } else if ( acked > txsi -> len ) { multiack = 1 ; e_t -> dlyack_rx += ( e_t -> dlyack_rx < DLYACK_SMOOTH ) ? 1 : 0 ; } else if ( acked == tp -> t_maxseg || acked == txsi -> len ) { e_t -> dlyack_rx -= ( e_t -> dlyack_rx > 0 ) ? 1 : 0 ; } } if ( e_t -> timestamp_errors < MAX_TS_ERR && ( to -> to_flags & TOF_TS ) != 0 && to -> to_tsecr ) { rts = to -> to_tsecr ; if ( ! e_t -> dlyack_rx && TSTMP_LT ( rts , txsi -> tx_ts ) ) break ; if ( TSTMP_GT ( rts , txsi -> tx_ts ) ) { if ( txsi -> flags & TXSI_RTT_MEASURE_START || measurenext ) { marked_packet_rtt ( txsi , e_t , tp , & measurenext , & measurenext_len , & rtt_bytes_adjust , OLD_TXSI ) ; } TAILQ_REMOVE ( & e_t -> txsegi_q , txsi , txsegi_lnk ) ; uma_zfree ( txseginfo_zone , txsi ) ; txsi = TAILQ_FIRST ( & e_t -> txsegi_q ) ; continue ; } if ( rts == txsi -> tx_ts && TSTMP_LT ( to -> to_tsval , txsi -> rx_ts ) ) { e_t -> timestamp_errors ++ ; } } if ( SEQ_LEQ ( ack , txsi -> seq ) ) break ; if ( ! e_t -> dlyack_rx || multiack || new_sacked_bytes ) { e_t -> rtt = tcp_ts_getticks ( ) - txsi -> tx_ts + 1 ; if ( e_t -> rtt < e_t -> minrtt || e_t -> minrtt == 0 ) e_t -> minrtt = e_t -> rtt ; if ( e_t -> rtt > e_t -> maxrtt || e_t -> maxrtt == 0 ) e_t -> maxrtt = e_t -> rtt ; } if ( txsi -> flags & TXSI_RTT_MEASURE_START || measurenext ) marked_packet_rtt ( txsi , e_t , tp , & measurenext , & measurenext_len , & rtt_bytes_adjust , CORRECT_ACK ) ; if ( txsi -> flags & TXSI_TSO ) { txsi -> len -= acked ; if ( txsi -> len > 0 ) { txsi -> seq += acked ; txsi -> flags &= ~ TXSI_RTT_MEASURE_START ; break ; } } TAILQ_REMOVE ( & e_t -> txsegi_q , txsi , txsegi_lnk ) ; uma_zfree ( txseginfo_zone , txsi ) ; break ; } if ( measurenext ) { marked_packet_rtt ( txsi , e_t , tp , & measurenext , & measurenext_len , & rtt_bytes_adjust , FORCED_MEASUREMENT ) ; } } return ( 0 ) ; }
Ertt_packet_measurements uses a small amount of state kept on each packet
 sent to match incoming acknowledgements.
Ertt_packet_measurements uses a small amount of state kept on each packet sent to match incoming acknowledgements .
/* Packet has provided new acknowledgements. */ /* Use last sacked data. */ /* Acknowledgement is acking more than this txsi. */ /*
			 * Guess if delayed acks are being used by the receiver.
			 *
			 * XXXDH: A simple heuristic that could be improved
			 */ /* Otherwise leave dlyack_rx the way it was. */ /*
			 * Time stamps are only to help match the txsi with the
			 * received acknowledgements.
			 */ /*
				 * Note: All packets sent with the offload will
				 * have the same time stamp. If we are sending
				 * on a fast interface and the t_maxseg is much
				 * smaller than one tick, this will be fine. The
				 * time stamp would be the same whether we were
				 * using tso or not. However, if the interface
				 * is slow, this will cause problems with the
				 * calculations. If the interface is slow, there
				 * is not reason to be using tso, and it should
				 * be turned off.
				 */ /*
				 * If there are too many time stamp errors, time
				 * stamps won't be trusted
				 */ /* Before this packet. */ /* When delayed acking is used, the
					 * reflected time stamp is of the first
					 * packet and thus may be before
					 * txsi->tx_ts.
					 */ /*
					 * If reflected time stamp is later than
					 * tx_tsi, then this txsi is old.
					 */ /*
					 * Segment received before sent!
					 * Something is wrong with the received
					 * timestamps so increment errors. If
					 * this keeps up we will ignore
					 * timestamps.
					 */ /*
			 * Acknowledging a sequence number before this txsi.
			 * If it is an old txsi that may have had the same seq
			 * numbers, it should have been removed if time stamps
			 * are being used.
			 */ /* Before first packet in txsi. */ /*
			 * Only ack > txsi->seq and ack <= txsi->seq+txsi->len
			 * past this point.
			 *
			 * If delayed acks are being used, an acknowledgement
			 * for a single segment will have been delayed by the
			 * receiver and will yield an inaccurate measurement. In
			 * this case, we only make the measurement if more than
			 * one segment is being acknowledged or sack is
			 * currently being used.
			 */ /* Make an accurate new measurement. */ /*
					 * This presumes ack for first bytes in
					 * txsi, this may not be true but it
					 * shouldn't cause problems for the
					 * timing.
					 *
					 * We remeasure RTT even though we only
					 * have a single txsi. The rationale
					 * behind this is that it is better to
					 * have a slightly inaccurate
					 * measurement than no additional
					 * measurement for the rest of the bulk
					 * transfer. Since TSO is only used on
					 * high speed interface cards, so the
					 * packets should be transmitted at line
					 * rate back to back with little
					 * difference in transmission times (in
					 * ticks).
					 */ /*
					 * Reset txsi measure flag so we don't
					 * use it for another RTT measurement.
					 */ /*
					 * There is still more data to be acked
					 * from tso bulk transmission, so we
					 * won't remove it from the TAILQ yet.
					 */ /*
			 * We need to do a RTT measurement. It won't be the best
			 * if we do it here.
			 */