Skip to content

Commit ed9208b

Browse files
committed
Merge branch 'udp-ipv6-use-scratch-helpers'
Paolo Abeni says: ==================== ipv6: udp: exploit dev_scratch helpers When bringing in the recent cache optimization for the UDP protocol, I forgot to leverage the newly introduced scratched area helpers in the UDPv6 code path. As a result, the UDPv6 implementation suffers some unnecessary performance penality when compared to v4. This series aim to bring back UDPv6 on equal footing in respect to v4. The first patch moves the shared helpers to the common include files, while the second uses them in the UDPv6 code. This gives 5-8% performance improvement for a system under flood with small UDPv6 packets. The performance delta is less than the one reported on the original patch set because the UDPv6 code path already leveraged some of the optimization. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents d97af30 + 67a5178 commit ed9208b

File tree

3 files changed

+70
-65
lines changed

3 files changed

+70
-65
lines changed

include/net/udp.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,67 @@ struct sock *__udp6_lib_lookup(struct net *net,
302302
struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
303303
__be16 sport, __be16 dport);
304304

305+
/* UDP uses skb->dev_scratch to cache as much information as possible and avoid
306+
* possibly multiple cache miss on dequeue()
307+
*/
308+
#if BITS_PER_LONG == 64
309+
310+
/* truesize, len and the bit needed to compute skb_csum_unnecessary will be on
311+
* cold cache lines at recvmsg time.
312+
* skb->len can be stored on 16 bits since the udp header has been already
313+
* validated and pulled.
314+
*/
315+
struct udp_dev_scratch {
316+
u32 truesize;
317+
u16 len;
318+
bool is_linear;
319+
bool csum_unnecessary;
320+
};
321+
322+
static inline unsigned int udp_skb_len(struct sk_buff *skb)
323+
{
324+
return ((struct udp_dev_scratch *)&skb->dev_scratch)->len;
325+
}
326+
327+
static inline bool udp_skb_csum_unnecessary(struct sk_buff *skb)
328+
{
329+
return ((struct udp_dev_scratch *)&skb->dev_scratch)->csum_unnecessary;
330+
}
331+
332+
static inline bool udp_skb_is_linear(struct sk_buff *skb)
333+
{
334+
return ((struct udp_dev_scratch *)&skb->dev_scratch)->is_linear;
335+
}
336+
337+
#else
338+
static inline unsigned int udp_skb_len(struct sk_buff *skb)
339+
{
340+
return skb->len;
341+
}
342+
343+
static inline bool udp_skb_csum_unnecessary(struct sk_buff *skb)
344+
{
345+
return skb_csum_unnecessary(skb);
346+
}
347+
348+
static inline bool udp_skb_is_linear(struct sk_buff *skb)
349+
{
350+
return !skb_is_nonlinear(skb);
351+
}
352+
#endif
353+
354+
static inline int copy_linear_skb(struct sk_buff *skb, int len, int off,
355+
struct iov_iter *to)
356+
{
357+
int n, copy = len - off;
358+
359+
n = copy_to_iter(skb->data + off, copy, to);
360+
if (n == copy)
361+
return 0;
362+
363+
return -EFAULT;
364+
}
365+
305366
/*
306367
* SNMP statistics for UDP and UDP-Lite
307368
*/

net/ipv4/udp.c

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,24 +1163,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
11631163
return ret;
11641164
}
11651165

1166-
/* Copy as much information as possible into skb->dev_scratch to avoid
1167-
* possibly multiple cache miss on dequeue();
1168-
*/
11691166
#if BITS_PER_LONG == 64
1170-
1171-
/* we can store multiple info here: truesize, len and the bit needed to
1172-
* compute skb_csum_unnecessary will be on cold cache lines at recvmsg
1173-
* time.
1174-
* skb->len can be stored on 16 bits since the udp header has been already
1175-
* validated and pulled.
1176-
*/
1177-
struct udp_dev_scratch {
1178-
u32 truesize;
1179-
u16 len;
1180-
bool is_linear;
1181-
bool csum_unnecessary;
1182-
};
1183-
11841167
static void udp_set_dev_scratch(struct sk_buff *skb)
11851168
{
11861169
struct udp_dev_scratch *scratch;
@@ -1197,22 +1180,6 @@ static int udp_skb_truesize(struct sk_buff *skb)
11971180
{
11981181
return ((struct udp_dev_scratch *)&skb->dev_scratch)->truesize;
11991182
}
1200-
1201-
static unsigned int udp_skb_len(struct sk_buff *skb)
1202-
{
1203-
return ((struct udp_dev_scratch *)&skb->dev_scratch)->len;
1204-
}
1205-
1206-
static bool udp_skb_csum_unnecessary(struct sk_buff *skb)
1207-
{
1208-
return ((struct udp_dev_scratch *)&skb->dev_scratch)->csum_unnecessary;
1209-
}
1210-
1211-
static bool udp_skb_is_linear(struct sk_buff *skb)
1212-
{
1213-
return ((struct udp_dev_scratch *)&skb->dev_scratch)->is_linear;
1214-
}
1215-
12161183
#else
12171184
static void udp_set_dev_scratch(struct sk_buff *skb)
12181185
{
@@ -1223,21 +1190,6 @@ static int udp_skb_truesize(struct sk_buff *skb)
12231190
{
12241191
return skb->dev_scratch;
12251192
}
1226-
1227-
static unsigned int udp_skb_len(struct sk_buff *skb)
1228-
{
1229-
return skb->len;
1230-
}
1231-
1232-
static bool udp_skb_csum_unnecessary(struct sk_buff *skb)
1233-
{
1234-
return skb_csum_unnecessary(skb);
1235-
}
1236-
1237-
static bool udp_skb_is_linear(struct sk_buff *skb)
1238-
{
1239-
return !skb_is_nonlinear(skb);
1240-
}
12411193
#endif
12421194

12431195
/* fully reclaim rmem/fwd memory allocated for skb */
@@ -1598,18 +1550,6 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags,
15981550
}
15991551
EXPORT_SYMBOL_GPL(__skb_recv_udp);
16001552

1601-
static int copy_linear_skb(struct sk_buff *skb, int len, int off,
1602-
struct iov_iter *to)
1603-
{
1604-
int n, copy = len - off;
1605-
1606-
n = copy_to_iter(skb->data + off, copy, to);
1607-
if (n == copy)
1608-
return 0;
1609-
1610-
return -EFAULT;
1611-
}
1612-
16131553
/*
16141554
* This should be easy, if there is something there we
16151555
* return it, otherwise we block.

net/ipv6/udp.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
362362
if (!skb)
363363
return err;
364364

365-
ulen = skb->len;
365+
ulen = udp_skb_len(skb);
366366
copied = len;
367367
if (copied > ulen - off)
368368
copied = ulen - off;
@@ -379,14 +379,18 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
379379

380380
if (copied < ulen || peeking ||
381381
(is_udplite && UDP_SKB_CB(skb)->partial_cov)) {
382-
checksum_valid = !udp_lib_checksum_complete(skb);
382+
checksum_valid = udp_skb_csum_unnecessary(skb) ||
383+
!__udp_lib_checksum_complete(skb);
383384
if (!checksum_valid)
384385
goto csum_copy_err;
385386
}
386387

387-
if (checksum_valid || skb_csum_unnecessary(skb))
388-
err = skb_copy_datagram_msg(skb, off, msg, copied);
389-
else {
388+
if (checksum_valid || udp_skb_csum_unnecessary(skb)) {
389+
if (udp_skb_is_linear(skb))
390+
err = copy_linear_skb(skb, copied, off, &msg->msg_iter);
391+
else
392+
err = skb_copy_datagram_msg(skb, off, msg, copied);
393+
} else {
390394
err = skb_copy_and_csum_datagram_msg(skb, off, msg);
391395
if (err == -EINVAL)
392396
goto csum_copy_err;

0 commit comments

Comments
 (0)