rxrpc: Generate a summary of the ACK state for later use

Generate a summary of the Tx buffer packet state when an ACK is received
for use in a later patch that does congestion management.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2016-09-24 18:05:26 +01:00
parent df0562a72d
commit 31a1b98950
2 changed files with 48 additions and 11 deletions

View File

@ -540,6 +540,20 @@ struct rxrpc_call {
/* transmission-phase ACK management */ /* transmission-phase ACK management */
rxrpc_serial_t acks_latest; /* serial number of latest ACK received */ rxrpc_serial_t acks_latest; /* serial number of latest ACK received */
rxrpc_seq_t acks_lowest_nak; /* Lowest NACK in the buffer (or ==tx_hard_ack) */
};
/*
* Summary of a new ACK and the changes it made.
*/
struct rxrpc_ack_summary {
u8 ack_reason;
u8 nr_acks; /* Number of ACKs in packet */
u8 nr_nacks; /* Number of NACKs in packet */
u8 nr_new_acks; /* Number of new ACKs in packet */
u8 nr_new_nacks; /* Number of new NACKs in packet */
u8 nr_rot_new_acks; /* Number of rotated new ACKs */
bool new_low_nack; /* T if new low NACK found */
}; };
enum rxrpc_skb_trace { enum rxrpc_skb_trace {

View File

@ -56,12 +56,20 @@ static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb,
/* /*
* Apply a hard ACK by advancing the Tx window. * Apply a hard ACK by advancing the Tx window.
*/ */
static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to) static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
struct rxrpc_ack_summary *summary)
{ {
struct sk_buff *skb, *list = NULL; struct sk_buff *skb, *list = NULL;
int ix; int ix;
u8 annotation; u8 annotation;
if (call->acks_lowest_nak == call->tx_hard_ack) {
call->acks_lowest_nak = to;
} else if (before_eq(call->acks_lowest_nak, to)) {
summary->new_low_nack = true;
call->acks_lowest_nak = to;
}
spin_lock(&call->lock); spin_lock(&call->lock);
while (before(call->tx_hard_ack, to)) { while (before(call->tx_hard_ack, to)) {
@ -77,6 +85,8 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to)
if (annotation & RXRPC_TX_ANNO_LAST) if (annotation & RXRPC_TX_ANNO_LAST)
set_bit(RXRPC_CALL_TX_LAST, &call->flags); set_bit(RXRPC_CALL_TX_LAST, &call->flags);
if ((annotation & RXRPC_TX_ANNO_MASK) != RXRPC_TX_ANNO_ACK)
summary->nr_rot_new_acks++;
} }
spin_unlock(&call->lock); spin_unlock(&call->lock);
@ -147,6 +157,7 @@ bad_state:
*/ */
static bool rxrpc_receiving_reply(struct rxrpc_call *call) static bool rxrpc_receiving_reply(struct rxrpc_call *call)
{ {
struct rxrpc_ack_summary summary = { 0 };
rxrpc_seq_t top = READ_ONCE(call->tx_top); rxrpc_seq_t top = READ_ONCE(call->tx_top);
if (call->ackr_reason) { if (call->ackr_reason) {
@ -159,7 +170,7 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call)
} }
if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags))
rxrpc_rotate_tx_window(call, top); rxrpc_rotate_tx_window(call, top, &summary);
if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) {
rxrpc_proto_abort("TXL", call, top); rxrpc_proto_abort("TXL", call, top);
return false; return false;
@ -508,7 +519,8 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
* the time the ACK was sent. * the time the ACK was sent.
*/ */
static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks, static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
rxrpc_seq_t seq, int nr_acks) rxrpc_seq_t seq, int nr_acks,
struct rxrpc_ack_summary *summary)
{ {
bool resend = false; bool resend = false;
int ix; int ix;
@ -521,14 +533,23 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
annotation &= ~RXRPC_TX_ANNO_MASK; annotation &= ~RXRPC_TX_ANNO_MASK;
switch (*acks++) { switch (*acks++) {
case RXRPC_ACK_TYPE_ACK: case RXRPC_ACK_TYPE_ACK:
summary->nr_acks++;
if (anno_type == RXRPC_TX_ANNO_ACK) if (anno_type == RXRPC_TX_ANNO_ACK)
continue; continue;
summary->nr_new_acks++;
call->rxtx_annotations[ix] = call->rxtx_annotations[ix] =
RXRPC_TX_ANNO_ACK | annotation; RXRPC_TX_ANNO_ACK | annotation;
break; break;
case RXRPC_ACK_TYPE_NACK: case RXRPC_ACK_TYPE_NACK:
if (!summary->nr_nacks &&
call->acks_lowest_nak != seq) {
call->acks_lowest_nak = seq;
summary->new_low_nack = true;
}
summary->nr_nacks++;
if (anno_type == RXRPC_TX_ANNO_NAK) if (anno_type == RXRPC_TX_ANNO_NAK)
continue; continue;
summary->nr_new_nacks++;
if (anno_type == RXRPC_TX_ANNO_RETRANS) if (anno_type == RXRPC_TX_ANNO_RETRANS)
continue; continue;
call->rxtx_annotations[ix] = call->rxtx_annotations[ix] =
@ -558,7 +579,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb, static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
u16 skew) u16 skew)
{ {
u8 ack_reason; struct rxrpc_ack_summary summary = { 0 };
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
union { union {
struct rxrpc_ackpacket ack; struct rxrpc_ackpacket ack;
@ -581,10 +602,10 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
first_soft_ack = ntohl(buf.ack.firstPacket); first_soft_ack = ntohl(buf.ack.firstPacket);
hard_ack = first_soft_ack - 1; hard_ack = first_soft_ack - 1;
nr_acks = buf.ack.nAcks; nr_acks = buf.ack.nAcks;
ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ? summary.ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ?
buf.ack.reason : RXRPC_ACK__INVALID); buf.ack.reason : RXRPC_ACK__INVALID);
trace_rxrpc_rx_ack(call, first_soft_ack, ack_reason, nr_acks); trace_rxrpc_rx_ack(call, first_soft_ack, summary.ack_reason, nr_acks);
_proto("Rx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }", _proto("Rx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
sp->hdr.serial, sp->hdr.serial,
@ -592,7 +613,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
first_soft_ack, first_soft_ack,
ntohl(buf.ack.previousPacket), ntohl(buf.ack.previousPacket),
acked_serial, acked_serial,
rxrpc_ack_names[ack_reason], rxrpc_ack_names[summary.ack_reason],
buf.ack.nAcks); buf.ack.nAcks);
if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE) if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE)
@ -649,12 +670,13 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
return rxrpc_proto_abort("AKN", call, 0); return rxrpc_proto_abort("AKN", call, 0);
if (after(hard_ack, call->tx_hard_ack)) if (after(hard_ack, call->tx_hard_ack))
rxrpc_rotate_tx_window(call, hard_ack); rxrpc_rotate_tx_window(call, hard_ack, &summary);
if (nr_acks > 0) { if (nr_acks > 0) {
if (skb_copy_bits(skb, sp->offset, buf.acks, nr_acks) < 0) if (skb_copy_bits(skb, sp->offset, buf.acks, nr_acks) < 0)
return rxrpc_proto_abort("XSA", call, 0); return rxrpc_proto_abort("XSA", call, 0);
rxrpc_input_soft_acks(call, buf.acks, first_soft_ack, nr_acks); rxrpc_input_soft_acks(call, buf.acks, first_soft_ack, nr_acks,
&summary);
} }
if (test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { if (test_bit(RXRPC_CALL_TX_LAST, &call->flags)) {
@ -669,11 +691,12 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
*/ */
static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb) static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb)
{ {
struct rxrpc_ack_summary summary = { 0 };
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
_proto("Rx ACKALL %%%u", sp->hdr.serial); _proto("Rx ACKALL %%%u", sp->hdr.serial);
rxrpc_rotate_tx_window(call, call->tx_top); rxrpc_rotate_tx_window(call, call->tx_top, &summary);
if (test_bit(RXRPC_CALL_TX_LAST, &call->flags)) if (test_bit(RXRPC_CALL_TX_LAST, &call->flags))
rxrpc_end_tx_phase(call, false, "ETL"); rxrpc_end_tx_phase(call, false, "ETL");
} }