Skip to content

Commit 8722014

Browse files
dhowellskuba-moo
authored andcommitted
rxrpc: Fix use of Don't Fragment flag
rxrpc normally has the Don't Fragment flag set on the UDP packets it transmits, except when it has decided that DATA packets aren't getting through - in which case it turns it off just for the DATA transmissions. This can be a problem, however, for RESPONSE packets that convey authentication and crypto data from the client to the server as ticket may be larger than can fit in the MTU. In such a case, rxrpc gets itself into an infinite loop as the sendmsg returns an error (EMSGSIZE), which causes rxkad_send_response() to return -EAGAIN - and the CHALLENGE packet is put back on the Rx queue to retry, leading to the I/O thread endlessly attempting to perform the transmission. Fix this by disabling DF on RESPONSE packets for now. The use of DF and best data MTU determination needs reconsidering at some point in the future. Fixes: 17926a7 ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") Reported-by: Marc Dionne <marc.dionne@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> cc: linux-afs@lists.infradead.org Acked-by: Paolo Abeni <pabeni@redhat.com> Link: https://lore.kernel.org/r/1581852.1704813048@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 844f104 commit 8722014

4 files changed

Lines changed: 17 additions & 5 deletions

File tree

net/rxrpc/ar-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ void rxrpc_send_version_request(struct rxrpc_local *local,
10791079
/*
10801080
* local_object.c
10811081
*/
1082+
void rxrpc_local_dont_fragment(const struct rxrpc_local *local, bool set);
10821083
struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc *);
10831084
struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *, enum rxrpc_local_trace);
10841085
struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *, enum rxrpc_local_trace);

net/rxrpc/local_object.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ static void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, int err,
3636
return ipv6_icmp_error(sk, skb, err, port, info, payload);
3737
}
3838

39+
/*
40+
* Set or clear the Don't Fragment flag on a socket.
41+
*/
42+
void rxrpc_local_dont_fragment(const struct rxrpc_local *local, bool set)
43+
{
44+
if (set)
45+
ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DO);
46+
else
47+
ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DONT);
48+
}
49+
3950
/*
4051
* Compare a local to an address. Return -ve, 0 or +ve to indicate less than,
4152
* same or greater than.
@@ -203,7 +214,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
203214
ip_sock_set_recverr(usk);
204215

205216
/* we want to set the don't fragment bit */
206-
ip_sock_set_mtu_discover(usk, IP_PMTUDISC_DO);
217+
rxrpc_local_dont_fragment(local, true);
207218

208219
/* We want receive timestamps. */
209220
sock_enable_timestamps(usk);

net/rxrpc/output.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,14 +494,12 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
494494
switch (conn->local->srx.transport.family) {
495495
case AF_INET6:
496496
case AF_INET:
497-
ip_sock_set_mtu_discover(conn->local->socket->sk,
498-
IP_PMTUDISC_DONT);
497+
rxrpc_local_dont_fragment(conn->local, false);
499498
rxrpc_inc_stat(call->rxnet, stat_tx_data_send_frag);
500499
ret = do_udp_sendmsg(conn->local->socket, &msg, len);
501500
conn->peer->last_tx_at = ktime_get_seconds();
502501

503-
ip_sock_set_mtu_discover(conn->local->socket->sk,
504-
IP_PMTUDISC_DO);
502+
rxrpc_local_dont_fragment(conn->local, true);
505503
break;
506504

507505
default:

net/rxrpc/rxkad.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,9 @@ static int rxkad_send_response(struct rxrpc_connection *conn,
724724
serial = atomic_inc_return(&conn->serial);
725725
whdr.serial = htonl(serial);
726726

727+
rxrpc_local_dont_fragment(conn->local, false);
727728
ret = kernel_sendmsg(conn->local->socket, &msg, iov, 3, len);
729+
rxrpc_local_dont_fragment(conn->local, true);
728730
if (ret < 0) {
729731
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
730732
rxrpc_tx_point_rxkad_response);

0 commit comments

Comments
 (0)