1

rxrpc: Extract useful fields from a received ACK to skb priv data

Extract useful fields from a received ACK packet into the skb private data
early on in the process of parsing incoming packets.  This makes the ACK
fields available even before we've matched the ACK up to a call and will
allow us to deal with path MTU discovery probe responses even after the
relevant call has been completed.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
This commit is contained in:
David Howells 2024-02-01 10:29:36 +00:00
parent 37473e4162
commit 4b68137a20
4 changed files with 44 additions and 37 deletions

View File

@ -198,8 +198,8 @@ struct rxrpc_host_header {
* - max 48 bytes (struct sk_buff::cb) * - max 48 bytes (struct sk_buff::cb)
*/ */
struct rxrpc_skb_priv { struct rxrpc_skb_priv {
struct rxrpc_connection *conn; /* Connection referred to (poke packet) */
union { union {
struct rxrpc_connection *conn; /* Connection referred to (poke packet) */
struct { struct {
u16 offset; /* Offset of data */ u16 offset; /* Offset of data */
u16 len; /* Length of data */ u16 len; /* Length of data */
@ -208,9 +208,12 @@ struct rxrpc_skb_priv {
}; };
struct { struct {
rxrpc_seq_t first_ack; /* First packet in acks table */ rxrpc_seq_t first_ack; /* First packet in acks table */
rxrpc_seq_t prev_ack; /* Highest seq seen */
rxrpc_serial_t acked_serial; /* Packet in response to (or 0) */
u8 reason; /* Reason for ack */
u8 nr_acks; /* Number of acks+nacks */ u8 nr_acks; /* Number of acks+nacks */
u8 nr_nacks; /* Number of nacks */ u8 nr_nacks; /* Number of nacks */
}; } ack;
}; };
struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */ struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */
}; };

View File

@ -93,12 +93,12 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
sp = rxrpc_skb(ack_skb); sp = rxrpc_skb(ack_skb);
ack = (void *)ack_skb->data + sizeof(struct rxrpc_wire_header); ack = (void *)ack_skb->data + sizeof(struct rxrpc_wire_header);
for (i = 0; i < sp->nr_acks; i++) { for (i = 0; i < sp->ack.nr_acks; i++) {
rxrpc_seq_t seq; rxrpc_seq_t seq;
if (ack->acks[i] & 1) if (ack->acks[i] & 1)
continue; continue;
seq = sp->first_ack + i; seq = sp->ack.first_ack + i;
if (after(txb->seq, transmitted)) if (after(txb->seq, transmitted))
break; break;
if (after(txb->seq, seq)) if (after(txb->seq, seq))

View File

@ -710,20 +710,19 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call,
rxrpc_seq_t seq) rxrpc_seq_t seq)
{ {
struct sk_buff *skb = call->cong_last_nack; struct sk_buff *skb = call->cong_last_nack;
struct rxrpc_ackpacket ack;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
unsigned int i, new_acks = 0, retained_nacks = 0; unsigned int i, new_acks = 0, retained_nacks = 0;
rxrpc_seq_t old_seq = sp->first_ack; rxrpc_seq_t old_seq = sp->ack.first_ack;
u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(ack); u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket);
if (after_eq(seq, old_seq + sp->nr_acks)) { if (after_eq(seq, old_seq + sp->ack.nr_acks)) {
summary->nr_new_acks += sp->nr_nacks; summary->nr_new_acks += sp->ack.nr_nacks;
summary->nr_new_acks += seq - (old_seq + sp->nr_acks); summary->nr_new_acks += seq - (old_seq + sp->ack.nr_acks);
summary->nr_retained_nacks = 0; summary->nr_retained_nacks = 0;
} else if (seq == old_seq) { } else if (seq == old_seq) {
summary->nr_retained_nacks = sp->nr_nacks; summary->nr_retained_nacks = sp->ack.nr_nacks;
} else { } else {
for (i = 0; i < sp->nr_acks; i++) { for (i = 0; i < sp->ack.nr_acks; i++) {
if (acks[i] == RXRPC_ACK_TYPE_NACK) { if (acks[i] == RXRPC_ACK_TYPE_NACK) {
if (before(old_seq + i, seq)) if (before(old_seq + i, seq))
new_acks++; new_acks++;
@ -736,7 +735,7 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call,
summary->nr_retained_nacks = retained_nacks; summary->nr_retained_nacks = retained_nacks;
} }
return old_seq + sp->nr_acks; return old_seq + sp->ack.nr_acks;
} }
/* /*
@ -756,10 +755,10 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call,
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
unsigned int i, old_nacks = 0; unsigned int i, old_nacks = 0;
rxrpc_seq_t lowest_nak = seq + sp->nr_acks; rxrpc_seq_t lowest_nak = seq + sp->ack.nr_acks;
u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket); u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket);
for (i = 0; i < sp->nr_acks; i++) { for (i = 0; i < sp->ack.nr_acks; i++) {
if (acks[i] == RXRPC_ACK_TYPE_ACK) { if (acks[i] == RXRPC_ACK_TYPE_ACK) {
summary->nr_acks++; summary->nr_acks++;
if (after_eq(seq, since)) if (after_eq(seq, since))
@ -771,7 +770,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call,
old_nacks++; old_nacks++;
} else { } else {
summary->nr_new_nacks++; summary->nr_new_nacks++;
sp->nr_nacks++; sp->ack.nr_nacks++;
} }
if (before(seq, lowest_nak)) if (before(seq, lowest_nak))
@ -832,7 +831,6 @@ static bool rxrpc_is_ack_valid(struct rxrpc_call *call,
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)
{ {
struct rxrpc_ack_summary summary = { 0 }; struct rxrpc_ack_summary summary = { 0 };
struct rxrpc_ackpacket ack;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_acktrailer trailer; struct rxrpc_acktrailer trailer;
rxrpc_serial_t ack_serial, acked_serial; rxrpc_serial_t ack_serial, acked_serial;
@ -841,29 +839,24 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
_enter(""); _enter("");
offset = sizeof(struct rxrpc_wire_header); offset = sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket);
if (skb_copy_bits(skb, offset, &ack, sizeof(ack)) < 0)
return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack);
offset += sizeof(ack);
ack_serial = sp->hdr.serial; ack_serial = sp->hdr.serial;
acked_serial = ntohl(ack.serial); acked_serial = sp->ack.acked_serial;
first_soft_ack = ntohl(ack.firstPacket); first_soft_ack = sp->ack.first_ack;
prev_pkt = ntohl(ack.previousPacket); prev_pkt = sp->ack.prev_ack;
hard_ack = first_soft_ack - 1; nr_acks = sp->ack.nr_acks;
nr_acks = ack.nAcks; hard_ack = first_soft_ack - 1;
sp->first_ack = first_soft_ack; summary.ack_reason = (sp->ack.reason < RXRPC_ACK__INVALID ?
sp->nr_acks = nr_acks; sp->ack.reason : RXRPC_ACK__INVALID);
summary.ack_reason = (ack.reason < RXRPC_ACK__INVALID ?
ack.reason : RXRPC_ACK__INVALID);
trace_rxrpc_rx_ack(call, ack_serial, acked_serial, trace_rxrpc_rx_ack(call, ack_serial, acked_serial,
first_soft_ack, prev_pkt, first_soft_ack, prev_pkt,
summary.ack_reason, nr_acks); summary.ack_reason, nr_acks);
rxrpc_inc_stat(call->rxnet, stat_rx_acks[ack.reason]); rxrpc_inc_stat(call->rxnet, stat_rx_acks[summary.ack_reason]);
if (acked_serial != 0) { if (acked_serial != 0) {
switch (ack.reason) { switch (summary.ack_reason) {
case RXRPC_ACK_PING_RESPONSE: case RXRPC_ACK_PING_RESPONSE:
rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
rxrpc_rtt_rx_ping_response); rxrpc_rtt_rx_ping_response);
@ -883,7 +876,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
* indicates that the client address changed due to NAT. The server * indicates that the client address changed due to NAT. The server
* lost the call because it switched to a different peer. * lost the call because it switched to a different peer.
*/ */
if (unlikely(ack.reason == RXRPC_ACK_EXCEEDS_WINDOW) && if (unlikely(summary.ack_reason == RXRPC_ACK_EXCEEDS_WINDOW) &&
first_soft_ack == 1 && first_soft_ack == 1 &&
prev_pkt == 0 && prev_pkt == 0 &&
rxrpc_is_client_call(call)) { rxrpc_is_client_call(call)) {
@ -896,7 +889,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
* indicate a change of address. However, we can retransmit the call * indicate a change of address. However, we can retransmit the call
* if we still have it buffered to the beginning. * if we still have it buffered to the beginning.
*/ */
if (unlikely(ack.reason == RXRPC_ACK_OUT_OF_SEQUENCE) && if (unlikely(summary.ack_reason == RXRPC_ACK_OUT_OF_SEQUENCE) &&
first_soft_ack == 1 && first_soft_ack == 1 &&
prev_pkt == 0 && prev_pkt == 0 &&
call->acks_hard_ack == 0 && call->acks_hard_ack == 0 &&
@ -937,7 +930,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
call->acks_first_seq = first_soft_ack; call->acks_first_seq = first_soft_ack;
call->acks_prev_seq = prev_pkt; call->acks_prev_seq = prev_pkt;
switch (ack.reason) { switch (summary.ack_reason) {
case RXRPC_ACK_PING: case RXRPC_ACK_PING:
break; break;
default: default:
@ -994,7 +987,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
rxrpc_congestion_management(call, skb, &summary, acked_serial); rxrpc_congestion_management(call, skb, &summary, acked_serial);
send_response: send_response:
if (ack.reason == RXRPC_ACK_PING) if (summary.ack_reason == RXRPC_ACK_PING)
rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial, rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial,
rxrpc_propose_ack_respond_to_ping); rxrpc_propose_ack_respond_to_ping);
else if (sp->hdr.flags & RXRPC_REQUEST_ACK) else if (sp->hdr.flags & RXRPC_REQUEST_ACK)

View File

@ -124,6 +124,7 @@ static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rxrpc_wire_header whdr; struct rxrpc_wire_header whdr;
struct rxrpc_ackpacket ack;
/* dig out the RxRPC connection details */ /* dig out the RxRPC connection details */
if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0)
@ -141,6 +142,16 @@ static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp,
sp->hdr.securityIndex = whdr.securityIndex; sp->hdr.securityIndex = whdr.securityIndex;
sp->hdr._rsvd = ntohs(whdr._rsvd); sp->hdr._rsvd = ntohs(whdr._rsvd);
sp->hdr.serviceId = ntohs(whdr.serviceId); sp->hdr.serviceId = ntohs(whdr.serviceId);
if (sp->hdr.type == RXRPC_PACKET_TYPE_ACK) {
if (skb_copy_bits(skb, sizeof(whdr), &ack, sizeof(ack)) < 0)
return rxrpc_bad_message(skb, rxrpc_badmsg_short_ack);
sp->ack.first_ack = ntohl(ack.firstPacket);
sp->ack.prev_ack = ntohl(ack.previousPacket);
sp->ack.acked_serial = ntohl(ack.serial);
sp->ack.reason = ack.reason;
sp->ack.nr_acks = ack.nAcks;
}
return true; return true;
} }