Skip to content

Commit

Permalink
Merge tag 'rxrpc-fixes-20180510' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fixes

Here are three fixes for AF_RXRPC and two tracepoints that were useful for
finding them:

 (1) Fix missing start of expect-Rx-by timeout on initial packet
     transmission so that calls will time out if the peer doesn't respond.

 (2) Fix error reception on AF_INET6 sockets by using the correct family of
     sockopts on the UDP transport socket.

 (3) Fix setting the minimum security level on kernel calls so that they
     can be encrypted.

 (4) Add a tracepoint to log ICMP/ICMP6 and other error reports from the
     transport socket.

 (5) Add a tracepoint to log UDP sendmsg failure so that we can find out if
     transmission failure occurred on the UDP socket.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 11, 2018
2 parents af5d018 + 6b47fe1 commit f010089
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 48 deletions.
85 changes: 85 additions & 0 deletions include/trace/events/rxrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define _TRACE_RXRPC_H

#include <linux/tracepoint.h>
#include <linux/errqueue.h>

/*
* Define enums for tracing information.
Expand Down Expand Up @@ -210,6 +211,20 @@ enum rxrpc_congest_change {
rxrpc_cong_saw_nack,
};

enum rxrpc_tx_fail_trace {
rxrpc_tx_fail_call_abort,
rxrpc_tx_fail_call_ack,
rxrpc_tx_fail_call_data_frag,
rxrpc_tx_fail_call_data_nofrag,
rxrpc_tx_fail_call_final_resend,
rxrpc_tx_fail_conn_abort,
rxrpc_tx_fail_conn_challenge,
rxrpc_tx_fail_conn_response,
rxrpc_tx_fail_reject,
rxrpc_tx_fail_version_keepalive,
rxrpc_tx_fail_version_reply,
};

#endif /* end __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY */

/*
Expand Down Expand Up @@ -437,6 +452,19 @@ enum rxrpc_congest_change {
EM(RXRPC_CALL_LOCAL_ERROR, "LocalError") \
E_(RXRPC_CALL_NETWORK_ERROR, "NetError")

#define rxrpc_tx_fail_traces \
EM(rxrpc_tx_fail_call_abort, "CallAbort") \
EM(rxrpc_tx_fail_call_ack, "CallAck") \
EM(rxrpc_tx_fail_call_data_frag, "CallDataFrag") \
EM(rxrpc_tx_fail_call_data_nofrag, "CallDataNofrag") \
EM(rxrpc_tx_fail_call_final_resend, "CallFinalResend") \
EM(rxrpc_tx_fail_conn_abort, "ConnAbort") \
EM(rxrpc_tx_fail_conn_challenge, "ConnChall") \
EM(rxrpc_tx_fail_conn_response, "ConnResp") \
EM(rxrpc_tx_fail_reject, "Reject") \
EM(rxrpc_tx_fail_version_keepalive, "VerKeepalive") \
E_(rxrpc_tx_fail_version_reply, "VerReply")

/*
* Export enum symbols via userspace.
*/
Expand All @@ -460,6 +488,7 @@ rxrpc_propose_ack_traces;
rxrpc_propose_ack_outcomes;
rxrpc_congest_modes;
rxrpc_congest_changes;
rxrpc_tx_fail_traces;

/*
* Now redefine the EM() and E_() macros to map the enums to the strings that
Expand Down Expand Up @@ -1374,6 +1403,62 @@ TRACE_EVENT(rxrpc_resend,
__entry->anno)
);

TRACE_EVENT(rxrpc_rx_icmp,
TP_PROTO(struct rxrpc_peer *peer, struct sock_extended_err *ee,
struct sockaddr_rxrpc *srx),

TP_ARGS(peer, ee, srx),

TP_STRUCT__entry(
__field(unsigned int, peer )
__field_struct(struct sock_extended_err, ee )
__field_struct(struct sockaddr_rxrpc, srx )
),

TP_fast_assign(
__entry->peer = peer->debug_id;
memcpy(&__entry->ee, ee, sizeof(__entry->ee));
memcpy(&__entry->srx, srx, sizeof(__entry->srx));
),

TP_printk("P=%08x o=%u t=%u c=%u i=%u d=%u e=%d %pISp",
__entry->peer,
__entry->ee.ee_origin,
__entry->ee.ee_type,
__entry->ee.ee_code,
__entry->ee.ee_info,
__entry->ee.ee_data,
__entry->ee.ee_errno,
&__entry->srx.transport)
);

TRACE_EVENT(rxrpc_tx_fail,
TP_PROTO(unsigned int debug_id, rxrpc_serial_t serial, int ret,
enum rxrpc_tx_fail_trace what),

TP_ARGS(debug_id, serial, ret, what),

TP_STRUCT__entry(
__field(unsigned int, debug_id )
__field(rxrpc_serial_t, serial )
__field(int, ret )
__field(enum rxrpc_tx_fail_trace, what )
),

TP_fast_assign(
__entry->debug_id = debug_id;
__entry->serial = serial;
__entry->ret = ret;
__entry->what = what;
),

TP_printk("c=%08x r=%x ret=%d %s",
__entry->debug_id,
__entry->serial,
__entry->ret,
__print_symbolic(__entry->what, rxrpc_tx_fail_traces))
);

#endif /* _TRACE_RXRPC_H */

/* This part must be outside protection */
Expand Down
2 changes: 1 addition & 1 deletion net/rxrpc/af_rxrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
memset(&cp, 0, sizeof(cp));
cp.local = rx->local;
cp.key = key;
cp.security_level = 0;
cp.security_level = rx->min_sec_level;
cp.exclusive = false;
cp.upgrade = upgrade;
cp.service_id = srx->srx_service;
Expand Down
1 change: 1 addition & 0 deletions net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ enum rxrpc_call_flag {
RXRPC_CALL_SEND_PING, /* A ping will need to be sent */
RXRPC_CALL_PINGING, /* Ping in process */
RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */
};

/*
Expand Down
11 changes: 8 additions & 3 deletions net/rxrpc/conn_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
} __attribute__((packed)) pkt;
struct rxrpc_ackinfo ack_info;
size_t len;
int ioc;
int ret, ioc;
u32 serial, mtu, call_id, padding;

_enter("%d", conn->debug_id);
Expand Down Expand Up @@ -135,10 +135,13 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
break;
}

kernel_sendmsg(conn->params.local->socket, &msg, iov, ioc, len);
ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, ioc, len);
conn->params.peer->last_tx_at = ktime_get_real();
if (ret < 0)
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
rxrpc_tx_fail_call_final_resend);

_leave("");
return;
}

/*
Expand Down Expand Up @@ -236,6 +239,8 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,

ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
if (ret < 0) {
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
rxrpc_tx_fail_conn_abort);
_debug("sendmsg failed: %d", ret);
return -EAGAIN;
}
Expand Down
2 changes: 1 addition & 1 deletion net/rxrpc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,
if (timo) {
unsigned long now = jiffies, expect_rx_by;

expect_rx_by = jiffies + timo;
expect_rx_by = now + timo;
WRITE_ONCE(call->expect_rx_by, expect_rx_by);
rxrpc_reduce_call_timer(call, expect_rx_by, now,
rxrpc_timer_set_for_normal);
Expand Down
3 changes: 2 additions & 1 deletion net/rxrpc/local_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ static void rxrpc_send_version_request(struct rxrpc_local *local,

ret = kernel_sendmsg(local->socket, &msg, iov, 2, len);
if (ret < 0)
_debug("sendmsg failed: %d", ret);
trace_rxrpc_tx_fail(local->debug_id, 0, ret,
rxrpc_tx_fail_version_reply);

_leave("");
}
Expand Down
57 changes: 42 additions & 15 deletions net/rxrpc/local_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,22 +134,49 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
}
}

/* we want to receive ICMP errors */
opt = 1;
ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
}
switch (local->srx.transport.family) {
case AF_INET:
/* we want to receive ICMP errors */
opt = 1;
ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
}

/* we want to set the don't fragment bit */
opt = IP_PMTUDISC_DO;
ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
/* we want to set the don't fragment bit */
opt = IP_PMTUDISC_DO;
ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
}
break;

case AF_INET6:
/* we want to receive ICMP errors */
opt = 1;
ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
}

/* we want to set the don't fragment bit */
opt = IPV6_PMTUDISC_DO;
ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_MTU_DISCOVER,
(char *) &opt, sizeof(opt));
if (ret < 0) {
_debug("setsockopt failed");
goto error;
}
break;

default:
BUG();
}

/* set the socket up */
Expand Down
34 changes: 32 additions & 2 deletions net/rxrpc/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
if (ping)
call->ping_time = now;
conn->params.peer->last_tx_at = ktime_get_real();
if (ret < 0)
trace_rxrpc_tx_fail(call->debug_id, serial, ret,
rxrpc_tx_fail_call_ack);

if (call->state < RXRPC_CALL_COMPLETE) {
if (ret < 0) {
Expand Down Expand Up @@ -294,6 +297,10 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
ret = kernel_sendmsg(conn->params.local->socket,
&msg, iov, 1, sizeof(pkt));
conn->params.peer->last_tx_at = ktime_get_real();
if (ret < 0)
trace_rxrpc_tx_fail(call->debug_id, serial, ret,
rxrpc_tx_fail_call_abort);


rxrpc_put_connection(conn);
return ret;
Expand Down Expand Up @@ -387,6 +394,9 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
conn->params.peer->last_tx_at = ktime_get_real();

up_read(&conn->params.local->defrag_sem);
if (ret < 0)
trace_rxrpc_tx_fail(call->debug_id, serial, ret,
rxrpc_tx_fail_call_data_nofrag);
if (ret == -EMSGSIZE)
goto send_fragmentable;

Expand Down Expand Up @@ -414,6 +424,17 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
rxrpc_timer_set_for_lost_ack);
}
}

if (sp->hdr.seq == 1 &&
!test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER,
&call->flags)) {
unsigned long nowj = jiffies, expect_rx_by;

expect_rx_by = nowj + call->next_rx_timo;
WRITE_ONCE(call->expect_rx_by, expect_rx_by);
rxrpc_reduce_call_timer(call, expect_rx_by, nowj,
rxrpc_timer_set_for_normal);
}
}

rxrpc_set_keepalive(call);
Expand Down Expand Up @@ -465,6 +486,10 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
#endif
}

if (ret < 0)
trace_rxrpc_tx_fail(call->debug_id, serial, ret,
rxrpc_tx_fail_call_data_frag);

up_write(&conn->params.local->defrag_sem);
goto done;
}
Expand All @@ -482,6 +507,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
struct kvec iov[2];
size_t size;
__be32 code;
int ret;

_enter("%d", local->debug_id);

Expand Down Expand Up @@ -516,7 +542,10 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
whdr.flags ^= RXRPC_CLIENT_INITIATED;
whdr.flags &= RXRPC_CLIENT_INITIATED;

kernel_sendmsg(local->socket, &msg, iov, 2, size);
ret = kernel_sendmsg(local->socket, &msg, iov, 2, size);
if (ret < 0)
trace_rxrpc_tx_fail(local->debug_id, 0, ret,
rxrpc_tx_fail_reject);
}

rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
Expand Down Expand Up @@ -567,7 +596,8 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer)

ret = kernel_sendmsg(peer->local->socket, &msg, iov, 2, len);
if (ret < 0)
_debug("sendmsg failed: %d", ret);
trace_rxrpc_tx_fail(peer->debug_id, 0, ret,
rxrpc_tx_fail_version_keepalive);

peer->last_tx_at = ktime_get_real();
_leave("");
Expand Down
Loading

0 comments on commit f010089

Please sign in to comment.