Skip to content

Commit

Permalink
tun: reserve extra headroom only when XDP is set
Browse files Browse the repository at this point in the history
We reserve headroom unconditionally which could cause unnecessary
stress on socket memory accounting because of increased trusesize. Fix
this by only reserve extra headroom when XDP is set.

Cc: Jakub Kicinski <kubakici@wp.pl>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
jasowang authored and davem330 committed Sep 5, 2017
1 parent 9e776f2 commit 7df1321
Showing 1 changed file with 18 additions and 8 deletions.
26 changes: 18 additions & 8 deletions drivers/net/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ do { \
#endif

#define TUN_HEADROOM 256
#define TUN_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD + TUN_HEADROOM)
#define TUN_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD)

/* TUN device flags */

Expand Down Expand Up @@ -1272,25 +1272,35 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
struct page_frag *alloc_frag = &current->task_frag;
struct sk_buff *skb;
struct bpf_prog *xdp_prog;
int buflen = SKB_DATA_ALIGN(len + TUN_RX_PAD) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
unsigned int delta = 0;
char *buf;
size_t copied;
bool xdp_xmit = false;
int err;
int err, pad = TUN_RX_PAD;

rcu_read_lock();
xdp_prog = rcu_dereference(tun->xdp_prog);
if (xdp_prog)
pad += TUN_HEADROOM;
buflen += SKB_DATA_ALIGN(len + pad);
rcu_read_unlock();

if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL)))
return ERR_PTR(-ENOMEM);

buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
copied = copy_page_from_iter(alloc_frag->page,
alloc_frag->offset + TUN_RX_PAD,
alloc_frag->offset + pad,
len, from);
if (copied != len)
return ERR_PTR(-EFAULT);

if (hdr->gso_type)
/* There's a small window that XDP may be set after the check
* of xdp_prog above, this should be rare and for simplicity
* we do XDP on skb in case the headroom is not enough.
*/
if (hdr->gso_type || !xdp_prog)
*generic_xdp = 1;
else
*generic_xdp = 0;
Expand All @@ -1303,7 +1313,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
u32 act;

xdp.data_hard_start = buf;
xdp.data = buf + TUN_RX_PAD;
xdp.data = buf + pad;
xdp.data_end = xdp.data + len;
orig_data = xdp.data;
act = bpf_prog_run_xdp(xdp_prog, &xdp);
Expand Down Expand Up @@ -1339,7 +1349,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
return ERR_PTR(-ENOMEM);
}

skb_reserve(skb, TUN_RX_PAD - delta);
skb_reserve(skb, pad - delta);
skb_put(skb, len + delta);
get_page(alloc_frag->page);
alloc_frag->offset += buflen;
Expand Down

0 comments on commit 7df1321

Please sign in to comment.