Skip to content

Commit

Permalink
rxrpc: Use the UDP encap_rcv hook
Browse files Browse the repository at this point in the history
Use the UDP encap_rcv hook to cut the bit out of the rxrpc packet reception
in which a packet is placed onto the UDP receive queue and then immediately
removed again by rxrpc.  Going via the queue in this manner seems like it
should be unnecessary.

This does, however, require the invention of a value to place in encap_type
as that's one of the conditions to switch packets out to the encap_rcv
hook.  Possibly the value doesn't actually matter for anything other than
sockopts on the UDP socket, which aren't accessible outside of rxrpc
anyway.

This seems to cut a bit of time out of the time elapsed between each
sk_buff being timestamped and turning up in rxrpc (the final number in the
following trace excerpts).  I measured this by making the rxrpc_rx_packet
trace point print the time elapsed between the skb being timestamped and
the current time (in ns), e.g.:

	... 424.278721: rxrpc_rx_packet: ...  ACK 25026

So doing a 512MiB DIO read from my test server, with an unmodified kernel:

	N       min     max     sum		mean    stddev
	27605   2626    7581    7.83992e+07     2840.04 181.029

and with the patch applied:

	N       min     max     sum		mean    stddev
	27547   1895    12165   6.77461e+07     2459.29 255.02

Signed-off-by: David Howells <dhowells@redhat.com>
  • Loading branch information
dhowells committed Oct 8, 2018
1 parent 2cfa227 commit 5271953
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 44 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ struct udphdr {
#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */
#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */
#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */
#define UDP_ENCAP_RXRPC 6

#endif /* _UAPI_LINUX_UDP_H */
2 changes: 1 addition & 1 deletion net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ void rxrpc_unpublish_service_conn(struct rxrpc_connection *);
/*
* input.c
*/
void rxrpc_data_ready(struct sock *);
int rxrpc_input_packet(struct sock *, struct sk_buff *);

/*
* insecure.c
Expand Down
50 changes: 12 additions & 38 deletions net/rxrpc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
* shut down and the local endpoint from going away, thus sk_user_data will not
* be cleared until this function returns.
*/
void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
{
struct rxrpc_connection *conn;
struct rxrpc_channel *chan;
Expand All @@ -1135,6 +1135,13 @@ void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)

_enter("%p", udp_sk);

if (skb->tstamp == 0)
skb->tstamp = ktime_get_real();

rxrpc_new_skb(skb, rxrpc_skb_rx_received);

skb_pull(skb, sizeof(struct udphdr));

/* The UDP protocol already released all skb resources;
* we are free to add our own data there.
*/
Expand All @@ -1148,8 +1155,8 @@ void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
static int lose;
if ((lose++ & 7) == 7) {
trace_rxrpc_rx_lose(sp);
rxrpc_lose_skb(skb, rxrpc_skb_rx_lost);
return;
rxrpc_free_skb(skb, rxrpc_skb_rx_lost);
return 0;
}
}

Expand Down Expand Up @@ -1332,7 +1339,7 @@ void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
out:
trace_rxrpc_rx_done(0, 0);
return;
return 0;

out_unlock:
rcu_read_unlock();
Expand Down Expand Up @@ -1371,38 +1378,5 @@ void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
trace_rxrpc_rx_done(skb->mark, skb->priority);
rxrpc_reject_packet(local, skb);
_leave(" [badmsg]");
}

void rxrpc_data_ready(struct sock *udp_sk)
{
struct sk_buff *skb;
int ret;

for (;;) {
skb = skb_recv_udp(udp_sk, 0, 1, &ret);
if (!skb) {
if (ret == -EAGAIN)
return;

/* If there was a transmission failure, we get an error
* here that we need to ignore.
*/
_debug("UDP socket error %d", ret);
continue;
}

rxrpc_new_skb(skb, rxrpc_skb_rx_received);

/* we'll probably need to checksum it (didn't call sock_recvmsg) */
if (skb_checksum_complete(skb)) {
rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
__UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INERRORS, 0);
_debug("csum failed");
continue;
}

__UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INDATAGRAMS, 0);

rxrpc_input_packet(udp_sk, skb);
}
return 0;
}
27 changes: 22 additions & 5 deletions net/rxrpc/local_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/ip.h>
#include <linux/hashtable.h>
#include <net/sock.h>
#include <net/udp.h>
#include <net/af_rxrpc.h>
#include "ar-internal.h"

Expand Down Expand Up @@ -108,7 +109,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
*/
static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
{
struct sock *sock;
struct sock *usk;
int ret, opt;

_enter("%p{%d,%d}",
Expand All @@ -123,10 +124,26 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
}

/* set the socket up */
sock = local->socket->sk;
sock->sk_user_data = local;
sock->sk_data_ready = rxrpc_data_ready;
sock->sk_error_report = rxrpc_error_report;
usk = local->socket->sk;
inet_sk(usk)->mc_loop = 0;

/* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
inet_inc_convert_csum(usk);

rcu_assign_sk_user_data(usk, local);

udp_sk(usk)->encap_type = UDP_ENCAP_RXRPC;
udp_sk(usk)->encap_rcv = rxrpc_input_packet;
udp_sk(usk)->encap_destroy = NULL;
udp_sk(usk)->gro_receive = NULL;
udp_sk(usk)->gro_complete = NULL;

udp_encap_enable();
#if IS_ENABLED(CONFIG_IPV6)
if (local->srx.transport.family == AF_INET6)
udpv6_encap_enable();
#endif
usk->sk_error_report = rxrpc_error_report;

/* if a local address was supplied then bind it */
if (local->srx.transport_len > sizeof(sa_family_t)) {
Expand Down

0 comments on commit 5271953

Please sign in to comment.