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:
parent
df0562a72d
commit
31a1b98950
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue