Commit cb891fa6 authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

udp6: fix jumbogram reception

Since commit 67a51780 ("ipv6: udp: leverage scratch area
helpers") udp6_recvmsg() read the skb len from the scratch area,
to avoid a cache miss.
But the UDP6 rx path support RFC 2675 UDPv6 jumbograms, and their
length exceeds the 16 bits available in the scratch area. As a side
effect the length returned by recvmsg() is:
<ingress datagram len> % (1<<16)

This commit addresses the issue allocating one more bit in the
IP6CB flags field and setting it for incoming jumbograms.
Such field is still in the first cacheline, so at recvmsg()
time we can check it and fallback to access skb->len if
required, without a measurable overhead.

Fixes: 67a51780 ("ipv6: udp: leverage scratch area helpers")
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ddab8282
...@@ -128,6 +128,7 @@ struct inet6_skb_parm { ...@@ -128,6 +128,7 @@ struct inet6_skb_parm {
#define IP6SKB_FRAGMENTED 16 #define IP6SKB_FRAGMENTED 16
#define IP6SKB_HOPBYHOP 32 #define IP6SKB_HOPBYHOP 32
#define IP6SKB_L3SLAVE 64 #define IP6SKB_L3SLAVE 64
#define IP6SKB_JUMBOGRAM 128
}; };
#if defined(CONFIG_NET_L3_MASTER_DEV) #if defined(CONFIG_NET_L3_MASTER_DEV)
...@@ -152,6 +153,11 @@ static inline int inet6_iif(const struct sk_buff *skb) ...@@ -152,6 +153,11 @@ static inline int inet6_iif(const struct sk_buff *skb)
return l3_slave ? skb->skb_iif : IP6CB(skb)->iif; return l3_slave ? skb->skb_iif : IP6CB(skb)->iif;
} }
static inline bool inet6_is_jumbogram(const struct sk_buff *skb)
{
return !!(IP6CB(skb)->flags & IP6SKB_JUMBOGRAM);
}
/* can not be used in TCP layer after tcp_v6_fill_cb */ /* can not be used in TCP layer after tcp_v6_fill_cb */
static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb) static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb)
{ {
......
...@@ -756,6 +756,7 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) ...@@ -756,6 +756,7 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
goto drop; goto drop;
IP6CB(skb)->flags |= IP6SKB_JUMBOGRAM;
return true; return true;
drop: drop:
......
...@@ -328,6 +328,15 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be ...@@ -328,6 +328,15 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be
EXPORT_SYMBOL_GPL(udp6_lib_lookup); EXPORT_SYMBOL_GPL(udp6_lib_lookup);
#endif #endif
/* do not use the scratch area len for jumbogram: their length execeeds the
* scratch area space; note that the IP6CB flags is still in the first
* cacheline, so checking for jumbograms is cheap
*/
static int udp6_skb_len(struct sk_buff *skb)
{
return unlikely(inet6_is_jumbogram(skb)) ? skb->len : udp_skb_len(skb);
}
/* /*
* This should be easy, if there is something there we * This should be easy, if there is something there we
* return it, otherwise we block. * return it, otherwise we block.
...@@ -358,7 +367,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -358,7 +367,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
if (!skb) if (!skb)
return err; return err;
ulen = udp_skb_len(skb); ulen = udp6_skb_len(skb);
copied = len; copied = len;
if (copied > ulen - off) if (copied > ulen - off)
copied = ulen - off; copied = ulen - off;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment