mirror of
https://github.com/torvalds/linux.git
synced 2026-05-05 23:05:25 -04:00
tap: Use tun's vnet-related code
tun and tap implements the same vnet-related features so reuse the code. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20250207-tun-v6-7-fb49cf8b103e@daynix.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
74212f20f3
commit
6a53fc5a87
@@ -26,75 +26,10 @@
|
||||
#include <linux/virtio_net.h>
|
||||
#include <linux/skb_array.h>
|
||||
|
||||
#include "tun_vnet.h"
|
||||
|
||||
#define TAP_IFFEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE)
|
||||
|
||||
#define TAP_VNET_LE 0x80000000
|
||||
#define TAP_VNET_BE 0x40000000
|
||||
|
||||
#ifdef CONFIG_TUN_VNET_CROSS_LE
|
||||
static inline bool tap_legacy_is_little_endian(struct tap_queue *q)
|
||||
{
|
||||
return q->flags & TAP_VNET_BE ? false :
|
||||
virtio_legacy_is_little_endian();
|
||||
}
|
||||
|
||||
static long tap_get_vnet_be(struct tap_queue *q, int __user *sp)
|
||||
{
|
||||
int s = !!(q->flags & TAP_VNET_BE);
|
||||
|
||||
if (put_user(s, sp))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long tap_set_vnet_be(struct tap_queue *q, int __user *sp)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (get_user(s, sp))
|
||||
return -EFAULT;
|
||||
|
||||
if (s)
|
||||
q->flags |= TAP_VNET_BE;
|
||||
else
|
||||
q->flags &= ~TAP_VNET_BE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline bool tap_legacy_is_little_endian(struct tap_queue *q)
|
||||
{
|
||||
return virtio_legacy_is_little_endian();
|
||||
}
|
||||
|
||||
static long tap_get_vnet_be(struct tap_queue *q, int __user *argp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long tap_set_vnet_be(struct tap_queue *q, int __user *argp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_TUN_VNET_CROSS_LE */
|
||||
|
||||
static inline bool tap_is_little_endian(struct tap_queue *q)
|
||||
{
|
||||
return q->flags & TAP_VNET_LE ||
|
||||
tap_legacy_is_little_endian(q);
|
||||
}
|
||||
|
||||
static inline u16 tap16_to_cpu(struct tap_queue *q, __virtio16 val)
|
||||
{
|
||||
return __virtio16_to_cpu(tap_is_little_endian(q), val);
|
||||
}
|
||||
|
||||
static inline __virtio16 cpu_to_tap16(struct tap_queue *q, u16 val)
|
||||
{
|
||||
return __cpu_to_virtio16(tap_is_little_endian(q), val);
|
||||
}
|
||||
|
||||
static struct proto tap_proto = {
|
||||
.name = "tap",
|
||||
.owner = THIS_MODULE,
|
||||
@@ -655,25 +590,13 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
|
||||
if (q->flags & IFF_VNET_HDR) {
|
||||
vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
|
||||
|
||||
err = -EINVAL;
|
||||
if (len < vnet_hdr_len)
|
||||
hdr_len = tun_vnet_hdr_get(vnet_hdr_len, q->flags, from, &vnet_hdr);
|
||||
if (hdr_len < 0) {
|
||||
err = hdr_len;
|
||||
goto err;
|
||||
len -= vnet_hdr_len;
|
||||
|
||||
err = -EFAULT;
|
||||
if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from))
|
||||
goto err;
|
||||
iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
|
||||
hdr_len = tap16_to_cpu(q, vnet_hdr.hdr_len);
|
||||
if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
|
||||
hdr_len = max(tap16_to_cpu(q, vnet_hdr.csum_start) +
|
||||
tap16_to_cpu(q, vnet_hdr.csum_offset) + 2,
|
||||
hdr_len);
|
||||
vnet_hdr.hdr_len = cpu_to_tap16(q, hdr_len);
|
||||
}
|
||||
err = -EINVAL;
|
||||
if (tap16_to_cpu(q, vnet_hdr.hdr_len) > len)
|
||||
goto err;
|
||||
|
||||
len -= vnet_hdr_len;
|
||||
}
|
||||
|
||||
err = -EINVAL;
|
||||
@@ -725,8 +648,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
|
||||
skb->dev = tap->dev;
|
||||
|
||||
if (vnet_hdr_len) {
|
||||
err = virtio_net_hdr_to_skb(skb, &vnet_hdr,
|
||||
tap_is_little_endian(q));
|
||||
err = tun_vnet_hdr_to_skb(q->flags, skb, &vnet_hdr);
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
drop_reason = SKB_DROP_REASON_DEV_HDR;
|
||||
@@ -789,23 +711,17 @@ static ssize_t tap_put_user(struct tap_queue *q,
|
||||
int total;
|
||||
|
||||
if (q->flags & IFF_VNET_HDR) {
|
||||
int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
|
||||
struct virtio_net_hdr vnet_hdr;
|
||||
|
||||
vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
|
||||
if (iov_iter_count(iter) < vnet_hdr_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
|
||||
tap_is_little_endian(q), true,
|
||||
vlan_hlen))
|
||||
BUG();
|
||||
ret = tun_vnet_hdr_from_skb(q->flags, NULL, skb, &vnet_hdr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
|
||||
sizeof(vnet_hdr))
|
||||
return -EFAULT;
|
||||
|
||||
iov_iter_advance(iter, vnet_hdr_len - sizeof(vnet_hdr));
|
||||
ret = tun_vnet_hdr_put(vnet_hdr_len, iter, &vnet_hdr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
total = vnet_hdr_len;
|
||||
total += skb->len;
|
||||
@@ -1064,42 +980,6 @@ static long tap_ioctl(struct file *file, unsigned int cmd,
|
||||
q->sk.sk_sndbuf = s;
|
||||
return 0;
|
||||
|
||||
case TUNGETVNETHDRSZ:
|
||||
s = q->vnet_hdr_sz;
|
||||
if (put_user(s, sp))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case TUNSETVNETHDRSZ:
|
||||
if (get_user(s, sp))
|
||||
return -EFAULT;
|
||||
if (s < (int)sizeof(struct virtio_net_hdr))
|
||||
return -EINVAL;
|
||||
|
||||
q->vnet_hdr_sz = s;
|
||||
return 0;
|
||||
|
||||
case TUNGETVNETLE:
|
||||
s = !!(q->flags & TAP_VNET_LE);
|
||||
if (put_user(s, sp))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case TUNSETVNETLE:
|
||||
if (get_user(s, sp))
|
||||
return -EFAULT;
|
||||
if (s)
|
||||
q->flags |= TAP_VNET_LE;
|
||||
else
|
||||
q->flags &= ~TAP_VNET_LE;
|
||||
return 0;
|
||||
|
||||
case TUNGETVNETBE:
|
||||
return tap_get_vnet_be(q, sp);
|
||||
|
||||
case TUNSETVNETBE:
|
||||
return tap_set_vnet_be(q, sp);
|
||||
|
||||
case TUNSETOFFLOAD:
|
||||
/* let the user check for future flags */
|
||||
if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
|
||||
@@ -1143,7 +1023,7 @@ static long tap_ioctl(struct file *file, unsigned int cmd,
|
||||
return ret;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
return tun_vnet_ioctl(&q->vnet_hdr_sz, &q->flags, cmd, sp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,7 +1070,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
|
||||
skb->protocol = eth_hdr(skb)->h_proto;
|
||||
|
||||
if (vnet_hdr_len) {
|
||||
err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q));
|
||||
err = tun_vnet_hdr_to_skb(q->flags, skb, gso);
|
||||
if (err)
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user