Commit 60df67b9 authored by Akihiko Odaki's avatar Akihiko Odaki Committed by Jakub Kicinski
Browse files

tun: Decouple vnet from tun_struct



Decouple vnet-related functions from tun_struct so that we can reuse
them for tap in the future.

Signed-off-by: default avatarAkihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20250207-tun-v6-3-fb49cf8b103e@daynix.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 07e8b3ba
Loading
Loading
Loading
Loading
+26 −25
Original line number Diff line number Diff line
@@ -298,17 +298,17 @@ static bool tun_napi_frags_enabled(const struct tun_file *tfile)
	return tfile->napi_frags_enabled;
}

static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
static inline bool tun_legacy_is_little_endian(unsigned int flags)
{
	bool be = IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
		  (tun->flags & TUN_VNET_BE);
		  (flags & TUN_VNET_BE);

	return !be && virtio_legacy_is_little_endian();
}

static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
static long tun_get_vnet_be(unsigned int flags, int __user *argp)
{
	int be = !!(tun->flags & TUN_VNET_BE);
	int be = !!(flags & TUN_VNET_BE);

	if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
		return -EINVAL;
@@ -319,7 +319,7 @@ static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
	return 0;
}

static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
static long tun_set_vnet_be(unsigned int *flags, int __user *argp)
{
	int be;

@@ -330,27 +330,26 @@ static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
		return -EFAULT;

	if (be)
		tun->flags |= TUN_VNET_BE;
		*flags |= TUN_VNET_BE;
	else
		tun->flags &= ~TUN_VNET_BE;
		*flags &= ~TUN_VNET_BE;

	return 0;
}

static inline bool tun_is_little_endian(struct tun_struct *tun)
static inline bool tun_is_little_endian(unsigned int flags)
{
	return tun->flags & TUN_VNET_LE ||
		tun_legacy_is_little_endian(tun);
	return flags & TUN_VNET_LE || tun_legacy_is_little_endian(flags);
}

static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
static inline u16 tun16_to_cpu(unsigned int flags, __virtio16 val)
{
	return __virtio16_to_cpu(tun_is_little_endian(tun), val);
	return __virtio16_to_cpu(tun_is_little_endian(flags), val);
}

static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val)
static inline __virtio16 cpu_to_tun16(unsigned int flags, u16 val)
{
	return __cpu_to_virtio16(tun_is_little_endian(tun), val);
	return __cpu_to_virtio16(tun_is_little_endian(flags), val);
}

static inline u32 tun_hashfn(u32 rxhash)
@@ -1766,6 +1765,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,

	if (tun->flags & IFF_VNET_HDR) {
		int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
		int flags = tun->flags;

		if (len < vnet_hdr_sz)
			return -EINVAL;
@@ -1774,11 +1774,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
		if (!copy_from_iter_full(&gso, sizeof(gso), from))
			return -EFAULT;

		hdr_len = tun16_to_cpu(tun, gso.hdr_len);
		hdr_len = tun16_to_cpu(flags, gso.hdr_len);

		if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
			hdr_len = max(tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2, hdr_len);
			gso.hdr_len = cpu_to_tun16(tun, hdr_len);
			hdr_len = max(tun16_to_cpu(flags, gso.csum_start) + tun16_to_cpu(flags, gso.csum_offset) + 2, hdr_len);
			gso.hdr_len = cpu_to_tun16(flags, hdr_len);
		}

		if (hdr_len > len)
@@ -1857,7 +1857,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
		}
	}

	if (virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun))) {
	if (virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun->flags))) {
		atomic_long_inc(&tun->rx_frame_errors);
		err = -EINVAL;
		goto free_skb;
@@ -2111,23 +2111,24 @@ static ssize_t tun_put_user(struct tun_struct *tun,

	if (vnet_hdr_sz) {
		struct virtio_net_hdr gso;
		int flags = tun->flags;

		if (iov_iter_count(iter) < vnet_hdr_sz)
			return -EINVAL;

		if (virtio_net_hdr_from_skb(skb, &gso,
					    tun_is_little_endian(tun), true,
					    tun_is_little_endian(flags), true,
					    vlan_hlen)) {
			struct skb_shared_info *sinfo = skb_shinfo(skb);

			if (net_ratelimit()) {
				netdev_err(tun->dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
					   sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
					   tun16_to_cpu(tun, gso.hdr_len));
					   sinfo->gso_type, tun16_to_cpu(flags, gso.gso_size),
					   tun16_to_cpu(flags, gso.hdr_len));
				print_hex_dump(KERN_ERR, "tun: ",
					       DUMP_PREFIX_NONE,
					       16, 1, skb->head,
					       min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
					       min((int)tun16_to_cpu(flags, gso.hdr_len), 64), true);
			}
			WARN_ON_ONCE(1);
			return -EINVAL;
@@ -2496,7 +2497,7 @@ static int tun_xdp_one(struct tun_struct *tun,
	skb_reserve(skb, xdp->data - xdp->data_hard_start);
	skb_put(skb, xdp->data_end - xdp->data);

	if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
	if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun->flags))) {
		atomic_long_inc(&tun->rx_frame_errors);
		kfree_skb(skb);
		ret = -EINVAL;
@@ -3325,11 +3326,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
		break;

	case TUNGETVNETBE:
		ret = tun_get_vnet_be(tun, argp);
		ret = tun_get_vnet_be(tun->flags, argp);
		break;

	case TUNSETVNETBE:
		ret = tun_set_vnet_be(tun, argp);
		ret = tun_set_vnet_be(&tun->flags, argp);
		break;

	case TUNATTACHFILTER: