net/tun: implement ndo_set_rx_headroom

ndo_set_rx_headroom controls the align value used by tun devices to
allocate skbs on frame reception.
When the xmit device adds a large encapsulation, this avoids an skb
head reallocation on forwarding.

The measured improvement when forwarding towards a vxlan dev with
frame size below the egress device MTU is as follow:

vxlan over ipv6, bridged: +6%
vxlan over ipv6, ovs: +7%

In case of ipv4 tunnels there is no improvement, since the tun
device default alignment provides enough headroom to avoid the skb
head reallocation.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Paolo Abeni 2016-02-26 10:45:40 +01:00 committed by David S. Miller
parent 3a927bc7cf
commit eaea34b23c
1 changed files with 16 additions and 1 deletions

View File

@ -187,6 +187,7 @@ struct tun_struct {
#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
NETIF_F_TSO6|NETIF_F_UFO) NETIF_F_TSO6|NETIF_F_UFO)
int align;
int vnet_hdr_sz; int vnet_hdr_sz;
int sndbuf; int sndbuf;
struct tap_filter txflt; struct tap_filter txflt;
@ -934,6 +935,17 @@ static void tun_poll_controller(struct net_device *dev)
return; return;
} }
#endif #endif
static void tun_set_headroom(struct net_device *dev, int new_hr)
{
struct tun_struct *tun = netdev_priv(dev);
if (new_hr < NET_SKB_PAD)
new_hr = NET_SKB_PAD;
tun->align = new_hr;
}
static const struct net_device_ops tun_netdev_ops = { static const struct net_device_ops tun_netdev_ops = {
.ndo_uninit = tun_net_uninit, .ndo_uninit = tun_net_uninit,
.ndo_open = tun_net_open, .ndo_open = tun_net_open,
@ -945,6 +957,7 @@ static const struct net_device_ops tun_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = tun_poll_controller, .ndo_poll_controller = tun_poll_controller,
#endif #endif
.ndo_set_rx_headroom = tun_set_headroom,
}; };
static const struct net_device_ops tap_netdev_ops = { static const struct net_device_ops tap_netdev_ops = {
@ -962,6 +975,7 @@ static const struct net_device_ops tap_netdev_ops = {
.ndo_poll_controller = tun_poll_controller, .ndo_poll_controller = tun_poll_controller,
#endif #endif
.ndo_features_check = passthru_features_check, .ndo_features_check = passthru_features_check,
.ndo_set_rx_headroom = tun_set_headroom,
}; };
static void tun_flow_init(struct tun_struct *tun) static void tun_flow_init(struct tun_struct *tun)
@ -1086,7 +1100,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
struct sk_buff *skb; struct sk_buff *skb;
size_t total_len = iov_iter_count(from); size_t total_len = iov_iter_count(from);
size_t len = total_len, align = NET_SKB_PAD, linear; size_t len = total_len, align = tun->align, linear;
struct virtio_net_hdr gso = { 0 }; struct virtio_net_hdr gso = { 0 };
int good_linear; int good_linear;
int copylen; int copylen;
@ -1694,6 +1708,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun->txflt.count = 0; tun->txflt.count = 0;
tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
tun->align = NET_SKB_PAD;
tun->filter_attached = false; tun->filter_attached = false;
tun->sndbuf = tfile->socket.sk->sk_sndbuf; tun->sndbuf = tfile->socket.sk->sk_sndbuf;