* [PATCH net-next v5 0/7] tun: Unify vnet implementation
@ 2025-02-05 6:22 Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE Akihiko Odaki
` (6 more replies)
0 siblings, 7 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
Cc: Willem de Bruijn
When I implemented virtio's hash-related features to tun/tap [1],
I found tun/tap does not fill the entire region reserved for the virtio
header, leaving some uninitialized hole in the middle of the buffer
after read()/recvmesg().
This series fills the uninitialized hole. More concretely, the
num_buffers field will be initialized with 1, and the other fields will
be inialized with 0. Setting the num_buffers field to 1 is mandated by
virtio 1.0 [2].
The change to virtio header is preceded by another change that refactors
tun and tap to unify their virtio-related code.
[1]: https://lore.kernel.org/r/20241008-rss-v5-0-f3cf68df005d@daynix.com
[2]: https://lore.kernel.org/r/20241227084256-mutt-send-email-mst@kernel.org/
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
Changes in v5:
- s/vnet_hdr_len_sz/vnet_hdr_sz/ for patch "tun: Decouple vnet handling"
(Willem de Bruijn)
- Changed to inline vnet implementations to TUN and TAP.
- Dropped patch "tun: Avoid double-tracking iov_iter length changes" and
"tap: Avoid double-tracking iov_iter length changes".
- Link to v4: https://lore.kernel.org/r/20250120-tun-v4-0-ee81dda03d7f@daynix.com
Changes in v4:
- s/sz/vnet_hdr_len_sz/ for patch "tun: Decouple vnet handling"
(Willem de Bruijn)
- Reverted to add CONFIG_TUN_VNET.
- Link to v3: https://lore.kernel.org/r/20250116-tun-v3-0-c6b2871e97f7@daynix.com
Changes in v3:
- Dropped changes to fill the vnet header.
- Splitted patch "tun: Unify vnet implementation".
- Reverted spurious changes in patch "tun: Unify vnet implementation".
- Merged tun_vnet.c into TAP.
- Link to v2: https://lore.kernel.org/r/20250109-tun-v2-0-388d7d5a287a@daynix.com
Changes in v2:
- Fixed num_buffers endian.
- Link to v1: https://lore.kernel.org/r/20250108-tun-v1-0-67d784b34374@daynix.com
---
Akihiko Odaki (7):
tun: Refactor CONFIG_TUN_VNET_CROSS_LE
tun: Keep hdr_len in tun_get_user()
tun: Decouple vnet from tun_struct
tun: Decouple vnet handling
tun: Extract the vnet handling code
tap: Keep hdr_len in tap_get_user()
tap: Use tun's vnet-related code
MAINTAINERS | 2 +-
drivers/net/tap.c | 168 ++++++------------------------------------
drivers/net/tun.c | 193 ++++++-------------------------------------------
drivers/net/tun_vnet.h | 184 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 231 insertions(+), 316 deletions(-)
---
base-commit: a32e14f8aef69b42826cf0998b068a43d486a9e9
change-id: 20241230-tun-66e10a49b0c7
Best regards,
--
Akihiko Odaki <akihiko.odaki@daynix.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 21:06 ` Willem de Bruijn
2025-02-05 6:22 ` [PATCH net-next v5 2/7] tun: Keep hdr_len in tun_get_user() Akihiko Odaki
` (5 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
Cc: Willem de Bruijn
Check IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) to save some lines and make
future changes easier.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/tun.c | 26 ++++++++------------------
1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e816aaba8e5f2ed06f8832f79553b6c976e75bb8..452fc5104260fe7ff5fdd5cedc5d2647cbe35c79 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -298,10 +298,10 @@ static bool tun_napi_frags_enabled(const struct tun_file *tfile)
return tfile->napi_frags_enabled;
}
-#ifdef CONFIG_TUN_VNET_CROSS_LE
static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
{
- return tun->flags & TUN_VNET_BE ? false :
+ return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
+ (tun->flags & TUN_VNET_BE)) &&
virtio_legacy_is_little_endian();
}
@@ -309,6 +309,9 @@ static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
{
int be = !!(tun->flags & TUN_VNET_BE);
+ if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+ return -EINVAL;
+
if (put_user(be, argp))
return -EFAULT;
@@ -319,6 +322,9 @@ static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
{
int be;
+ if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+ return -EINVAL;
+
if (get_user(be, argp))
return -EFAULT;
@@ -329,22 +335,6 @@ static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
return 0;
}
-#else
-static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
-{
- return virtio_legacy_is_little_endian();
-}
-
-static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
-{
- return -EINVAL;
-}
-
-static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
-{
- return -EINVAL;
-}
-#endif /* CONFIG_TUN_VNET_CROSS_LE */
static inline bool tun_is_little_endian(struct tun_struct *tun)
{
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 2/7] tun: Keep hdr_len in tun_get_user()
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 3/7] tun: Decouple vnet from tun_struct Akihiko Odaki
` (4 subsequent siblings)
6 siblings, 0 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
Cc: Willem de Bruijn
hdr_len is repeatedly used so keep it in a local variable.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/tun.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 452fc5104260fe7ff5fdd5cedc5d2647cbe35c79..9d4aabc3b63c8f9baab82d7ab2bba567e9075484 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1746,6 +1746,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
struct virtio_net_hdr gso = { 0 };
int good_linear;
int copylen;
+ int hdr_len = 0;
bool zerocopy = false;
int err;
u32 rxhash = 0;
@@ -1772,19 +1773,21 @@ 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;
- if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len))
- gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2);
+ hdr_len = tun16_to_cpu(tun, gso.hdr_len);
- if (tun16_to_cpu(tun, gso.hdr_len) > 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);
+ }
+
+ if (hdr_len > len)
return -EINVAL;
iov_iter_advance(from, vnet_hdr_sz - sizeof(gso));
}
if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
align += NET_IP_ALIGN;
- if (unlikely(len < ETH_HLEN ||
- (gso.hdr_len && tun16_to_cpu(tun, gso.hdr_len) < ETH_HLEN)))
+ if (unlikely(len < ETH_HLEN || (hdr_len && hdr_len < ETH_HLEN)))
return -EINVAL;
}
@@ -1797,9 +1800,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
* enough room for skb expand head in case it is used.
* The rest of the buffer is mapped from userspace.
*/
- copylen = gso.hdr_len ? tun16_to_cpu(tun, gso.hdr_len) : GOODCOPY_LEN;
- if (copylen > good_linear)
- copylen = good_linear;
+ copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear);
linear = copylen;
iov_iter_advance(&i, copylen);
if (iov_iter_npages(&i, INT_MAX) <= MAX_SKB_FRAGS)
@@ -1820,10 +1821,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
} else {
if (!zerocopy) {
copylen = len;
- if (tun16_to_cpu(tun, gso.hdr_len) > good_linear)
- linear = good_linear;
- else
- linear = tun16_to_cpu(tun, gso.hdr_len);
+ linear = min(hdr_len, good_linear);
}
if (frags) {
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 3/7] tun: Decouple vnet from tun_struct
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 2/7] tun: Keep hdr_len in tun_get_user() Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 4/7] tun: Decouple vnet handling Akihiko Odaki
` (3 subsequent siblings)
6 siblings, 0 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
Cc: Willem de Bruijn
Decouple vnet-related functions from tun_struct so that we can reuse
them for tap in the future.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/tun.c | 51 ++++++++++++++++++++++++++-------------------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9d4aabc3b63c8f9baab82d7ab2bba567e9075484..8ddd4b352f0307e52cdff75254b5ac1d259d51f8 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -298,16 +298,16 @@ 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)
{
return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
- (tun->flags & TUN_VNET_BE)) &&
+ (flags & TUN_VNET_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;
@@ -318,7 +318,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;
@@ -329,27 +329,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)
@@ -1765,6 +1764,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;
@@ -1773,11 +1773,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)
@@ -1856,7 +1856,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;
@@ -2110,23 +2110,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;
@@ -2495,7 +2496,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;
@@ -3324,11 +3325,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:
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 4/7] tun: Decouple vnet handling
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
` (2 preceding siblings ...)
2025-02-05 6:22 ` [PATCH net-next v5 3/7] tun: Decouple vnet from tun_struct Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 5/7] tun: Extract the vnet handling code Akihiko Odaki
` (2 subsequent siblings)
6 siblings, 0 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
Cc: Willem de Bruijn
Decouple the vnet handling code so that we can reuse it for tap.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/tun.c | 237 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 139 insertions(+), 98 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 8ddd4b352f0307e52cdff75254b5ac1d259d51f8..5bd1c21032ed673ba8e39dd5a488cce11599855b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -351,6 +351,127 @@ static inline __virtio16 cpu_to_tun16(unsigned int flags, u16 val)
return __cpu_to_virtio16(tun_is_little_endian(flags), val);
}
+static long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
+ unsigned int cmd, int __user *sp)
+{
+ int s;
+
+ switch (cmd) {
+ case TUNGETVNETHDRSZ:
+ s = *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;
+
+ *vnet_hdr_sz = s;
+ return 0;
+
+ case TUNGETVNETLE:
+ s = !!(*flags & TUN_VNET_LE);
+ if (put_user(s, sp))
+ return -EFAULT;
+ return 0;
+
+ case TUNSETVNETLE:
+ if (get_user(s, sp))
+ return -EFAULT;
+ if (s)
+ *flags |= TUN_VNET_LE;
+ else
+ *flags &= ~TUN_VNET_LE;
+ return 0;
+
+ case TUNGETVNETBE:
+ return tun_get_vnet_be(*flags, sp);
+
+ case TUNSETVNETBE:
+ return tun_set_vnet_be(flags, sp);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from,
+ struct virtio_net_hdr *hdr)
+{
+ u16 hdr_len;
+
+ if (iov_iter_count(from) < sz)
+ return -EINVAL;
+
+ if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
+ return -EFAULT;
+
+ hdr_len = tun16_to_cpu(flags, hdr->hdr_len);
+
+ if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+ hdr_len = max(tun16_to_cpu(flags, hdr->csum_start) + tun16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
+ hdr->hdr_len = cpu_to_tun16(flags, hdr_len);
+ }
+
+ if (hdr_len > iov_iter_count(from))
+ return -EINVAL;
+
+ iov_iter_advance(from, sz - sizeof(*hdr));
+
+ return hdr_len;
+}
+
+static int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
+ const struct virtio_net_hdr *hdr)
+{
+ if (unlikely(iov_iter_count(iter) < sz))
+ return -EINVAL;
+
+ if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
+ return -EFAULT;
+
+ iov_iter_advance(iter, sz - sizeof(*hdr));
+
+ return 0;
+}
+
+static int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
+ const struct virtio_net_hdr *hdr)
+{
+ return virtio_net_hdr_to_skb(skb, hdr, tun_is_little_endian(flags));
+}
+
+static int tun_vnet_hdr_from_skb(unsigned int flags,
+ const struct net_device *dev,
+ const struct sk_buff *skb,
+ struct virtio_net_hdr *hdr)
+{
+ int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
+
+ if (virtio_net_hdr_from_skb(skb, hdr,
+ tun_is_little_endian(flags), true,
+ vlan_hlen)) {
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+ if (net_ratelimit()) {
+ netdev_err(dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
+ sinfo->gso_type, tun16_to_cpu(flags, hdr->gso_size),
+ tun16_to_cpu(flags, hdr->hdr_len));
+ print_hex_dump(KERN_ERR, "tun: ",
+ DUMP_PREFIX_NONE,
+ 16, 1, skb->head,
+ min(tun16_to_cpu(flags, hdr->hdr_len), 64), true);
+ }
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static inline u32 tun_hashfn(u32 rxhash)
{
return rxhash & TUN_MASK_FLOW_ENTRIES;
@@ -1764,25 +1885,12 @@ 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;
- len -= vnet_hdr_sz;
-
- if (!copy_from_iter_full(&gso, sizeof(gso), from))
- return -EFAULT;
-
- hdr_len = tun16_to_cpu(flags, gso.hdr_len);
- if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- 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);
- }
+ hdr_len = tun_vnet_hdr_get(vnet_hdr_sz, tun->flags, from, &gso);
+ if (hdr_len < 0)
+ return hdr_len;
- if (hdr_len > len)
- return -EINVAL;
- iov_iter_advance(from, vnet_hdr_sz - sizeof(gso));
+ len -= vnet_hdr_sz;
}
if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
@@ -1856,7 +1964,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->flags))) {
+ if (tun_vnet_hdr_to_skb(tun->flags, skb, &gso)) {
atomic_long_inc(&tun->rx_frame_errors);
err = -EINVAL;
goto free_skb;
@@ -2051,18 +2159,15 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun,
{
int vnet_hdr_sz = 0;
size_t size = xdp_frame->len;
- size_t ret;
+ ssize_t ret;
if (tun->flags & IFF_VNET_HDR) {
struct virtio_net_hdr gso = { 0 };
vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
- if (unlikely(iov_iter_count(iter) < vnet_hdr_sz))
- return -EINVAL;
- if (unlikely(copy_to_iter(&gso, sizeof(gso), iter) !=
- sizeof(gso)))
- return -EFAULT;
- iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso));
+ ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso);
+ if (ret)
+ return ret;
}
ret = copy_to_iter(xdp_frame->data, size, iter) + vnet_hdr_sz;
@@ -2085,6 +2190,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
int vlan_offset = 0;
int vlan_hlen = 0;
int vnet_hdr_sz = 0;
+ int ret;
if (skb_vlan_tag_present(skb))
vlan_hlen = VLAN_HLEN;
@@ -2110,33 +2216,14 @@ 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(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(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(flags, gso.hdr_len), 64), true);
- }
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
- if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
- return -EFAULT;
+ ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso);
+ if (ret)
+ return ret;
- iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso));
+ ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso);
+ if (ret)
+ return ret;
}
if (vlan_hlen) {
@@ -2496,7 +2583,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->flags))) {
+ if (tun_vnet_hdr_to_skb(tun->flags, skb, gso)) {
atomic_long_inc(&tun->rx_frame_errors);
kfree_skb(skb);
ret = -EINVAL;
@@ -3080,8 +3167,6 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
kgid_t group;
int ifindex;
int sndbuf;
- int vnet_hdr_sz;
- int le;
int ret;
bool do_notify = false;
@@ -3288,50 +3373,6 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
tun_set_sndbuf(tun);
break;
- case TUNGETVNETHDRSZ:
- vnet_hdr_sz = tun->vnet_hdr_sz;
- if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz)))
- ret = -EFAULT;
- break;
-
- case TUNSETVNETHDRSZ:
- if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) {
- ret = -EFAULT;
- break;
- }
- if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) {
- ret = -EINVAL;
- break;
- }
-
- tun->vnet_hdr_sz = vnet_hdr_sz;
- break;
-
- case TUNGETVNETLE:
- le = !!(tun->flags & TUN_VNET_LE);
- if (put_user(le, (int __user *)argp))
- ret = -EFAULT;
- break;
-
- case TUNSETVNETLE:
- if (get_user(le, (int __user *)argp)) {
- ret = -EFAULT;
- break;
- }
- if (le)
- tun->flags |= TUN_VNET_LE;
- else
- tun->flags &= ~TUN_VNET_LE;
- break;
-
- case TUNGETVNETBE:
- ret = tun_get_vnet_be(tun->flags, argp);
- break;
-
- case TUNSETVNETBE:
- ret = tun_set_vnet_be(&tun->flags, argp);
- break;
-
case TUNATTACHFILTER:
/* Can be set only for TAPs */
ret = -EINVAL;
@@ -3387,7 +3428,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
break;
default:
- ret = -EINVAL;
+ ret = tun_vnet_ioctl(&tun->vnet_hdr_sz, &tun->flags, cmd, argp);
break;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 5/7] tun: Extract the vnet handling code
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
` (3 preceding siblings ...)
2025-02-05 6:22 ` [PATCH net-next v5 4/7] tun: Decouple vnet handling Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 21:12 ` Willem de Bruijn
2025-02-05 6:22 ` [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user() Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 7/7] tap: Use tun's vnet-related code Akihiko Odaki
6 siblings, 1 reply; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
The vnet handling code will be reused by tap.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
MAINTAINERS | 2 +-
drivers/net/tun.c | 179 +----------------------------------------------
drivers/net/tun_vnet.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 187 insertions(+), 178 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 910305c11e8a882da5b49ce5bd55011b93f28c32..bc32b7e23c79ab80b19c8207f14c5e51a47ec89f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23902,7 +23902,7 @@ W: http://vtun.sourceforge.net/tun
F: Documentation/networking/tuntap.rst
F: arch/um/os-Linux/drivers/
F: drivers/net/tap.c
-F: drivers/net/tun.c
+F: drivers/net/tun*
TURBOCHANNEL SUBSYSTEM
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5bd1c21032ed673ba8e39dd5a488cce11599855b..b14231a743915c2851eaae49d757b763ec4a8841 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -83,6 +83,8 @@
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
+#include "tun_vnet.h"
+
static void tun_default_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd);
@@ -94,9 +96,6 @@ static void tun_default_link_ksettings(struct net_device *dev,
* overload it to mean fasync when stored there.
*/
#define TUN_FASYNC IFF_ATTACH_QUEUE
-/* High bits in flags field are unused. */
-#define TUN_VNET_LE 0x80000000
-#define TUN_VNET_BE 0x40000000
#define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS)
@@ -298,180 +297,6 @@ static bool tun_napi_frags_enabled(const struct tun_file *tfile)
return tfile->napi_frags_enabled;
}
-static inline bool tun_legacy_is_little_endian(unsigned int flags)
-{
- return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
- (flags & TUN_VNET_BE)) &&
- virtio_legacy_is_little_endian();
-}
-
-static long tun_get_vnet_be(unsigned int flags, int __user *argp)
-{
- int be = !!(flags & TUN_VNET_BE);
-
- if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
- return -EINVAL;
-
- if (put_user(be, argp))
- return -EFAULT;
-
- return 0;
-}
-
-static long tun_set_vnet_be(unsigned int *flags, int __user *argp)
-{
- int be;
-
- if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
- return -EINVAL;
-
- if (get_user(be, argp))
- return -EFAULT;
-
- if (be)
- *flags |= TUN_VNET_BE;
- else
- *flags &= ~TUN_VNET_BE;
-
- return 0;
-}
-
-static inline bool tun_is_little_endian(unsigned int flags)
-{
- return flags & TUN_VNET_LE || tun_legacy_is_little_endian(flags);
-}
-
-static inline u16 tun16_to_cpu(unsigned int flags, __virtio16 val)
-{
- return __virtio16_to_cpu(tun_is_little_endian(flags), val);
-}
-
-static inline __virtio16 cpu_to_tun16(unsigned int flags, u16 val)
-{
- return __cpu_to_virtio16(tun_is_little_endian(flags), val);
-}
-
-static long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
- unsigned int cmd, int __user *sp)
-{
- int s;
-
- switch (cmd) {
- case TUNGETVNETHDRSZ:
- s = *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;
-
- *vnet_hdr_sz = s;
- return 0;
-
- case TUNGETVNETLE:
- s = !!(*flags & TUN_VNET_LE);
- if (put_user(s, sp))
- return -EFAULT;
- return 0;
-
- case TUNSETVNETLE:
- if (get_user(s, sp))
- return -EFAULT;
- if (s)
- *flags |= TUN_VNET_LE;
- else
- *flags &= ~TUN_VNET_LE;
- return 0;
-
- case TUNGETVNETBE:
- return tun_get_vnet_be(*flags, sp);
-
- case TUNSETVNETBE:
- return tun_set_vnet_be(flags, sp);
-
- default:
- return -EINVAL;
- }
-}
-
-static int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from,
- struct virtio_net_hdr *hdr)
-{
- u16 hdr_len;
-
- if (iov_iter_count(from) < sz)
- return -EINVAL;
-
- if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
- return -EFAULT;
-
- hdr_len = tun16_to_cpu(flags, hdr->hdr_len);
-
- if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- hdr_len = max(tun16_to_cpu(flags, hdr->csum_start) + tun16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
- hdr->hdr_len = cpu_to_tun16(flags, hdr_len);
- }
-
- if (hdr_len > iov_iter_count(from))
- return -EINVAL;
-
- iov_iter_advance(from, sz - sizeof(*hdr));
-
- return hdr_len;
-}
-
-static int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
- const struct virtio_net_hdr *hdr)
-{
- if (unlikely(iov_iter_count(iter) < sz))
- return -EINVAL;
-
- if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
- return -EFAULT;
-
- iov_iter_advance(iter, sz - sizeof(*hdr));
-
- return 0;
-}
-
-static int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
- const struct virtio_net_hdr *hdr)
-{
- return virtio_net_hdr_to_skb(skb, hdr, tun_is_little_endian(flags));
-}
-
-static int tun_vnet_hdr_from_skb(unsigned int flags,
- const struct net_device *dev,
- const struct sk_buff *skb,
- struct virtio_net_hdr *hdr)
-{
- int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
-
- if (virtio_net_hdr_from_skb(skb, hdr,
- tun_is_little_endian(flags), true,
- vlan_hlen)) {
- struct skb_shared_info *sinfo = skb_shinfo(skb);
-
- if (net_ratelimit()) {
- netdev_err(dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
- sinfo->gso_type, tun16_to_cpu(flags, hdr->gso_size),
- tun16_to_cpu(flags, hdr->hdr_len));
- print_hex_dump(KERN_ERR, "tun: ",
- DUMP_PREFIX_NONE,
- 16, 1, skb->head,
- min(tun16_to_cpu(flags, hdr->hdr_len), 64), true);
- }
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
-
- return 0;
-}
-
static inline u32 tun_hashfn(u32 rxhash)
{
return rxhash & TUN_MASK_FLOW_ENTRIES;
diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc5e9ec9d04cc8357504af23b1552af71155d329
--- /dev/null
+++ b/drivers/net/tun_vnet.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef TUN_VNET_H
+#define TUN_VNET_H
+
+/* High bits in flags field are unused. */
+#define TUN_VNET_LE 0x80000000
+#define TUN_VNET_BE 0x40000000
+
+static inline bool tun_vnet_legacy_is_little_endian(unsigned int flags)
+{
+ return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
+ (flags & TUN_VNET_BE)) &&
+ virtio_legacy_is_little_endian();
+}
+
+static inline long tun_get_vnet_be(unsigned int flags, int __user *argp)
+{
+ int be = !!(flags & TUN_VNET_BE);
+
+ if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+ return -EINVAL;
+
+ if (put_user(be, argp))
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline long tun_set_vnet_be(unsigned int *flags, int __user *argp)
+{
+ int be;
+
+ if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+ return -EINVAL;
+
+ if (get_user(be, argp))
+ return -EFAULT;
+
+ if (be)
+ *flags |= TUN_VNET_BE;
+ else
+ *flags &= ~TUN_VNET_BE;
+
+ return 0;
+}
+
+static inline bool tun_vnet_is_little_endian(unsigned int flags)
+{
+ return flags & TUN_VNET_LE || tun_vnet_legacy_is_little_endian(flags);
+}
+
+static inline u16 tun_vnet16_to_cpu(unsigned int flags, __virtio16 val)
+{
+ return __virtio16_to_cpu(tun_vnet_is_little_endian(flags), val);
+}
+
+static inline __virtio16 cpu_to_tun_vnet16(unsigned int flags, u16 val)
+{
+ return __cpu_to_virtio16(tun_vnet_is_little_endian(flags), val);
+}
+
+static inline long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
+ unsigned int cmd, int __user *sp)
+{
+ int s;
+
+ switch (cmd) {
+ case TUNGETVNETHDRSZ:
+ s = *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;
+
+ *vnet_hdr_sz = s;
+ return 0;
+
+ case TUNGETVNETLE:
+ s = !!(*flags & TUN_VNET_LE);
+ if (put_user(s, sp))
+ return -EFAULT;
+ return 0;
+
+ case TUNSETVNETLE:
+ if (get_user(s, sp))
+ return -EFAULT;
+ if (s)
+ *flags |= TUN_VNET_LE;
+ else
+ *flags &= ~TUN_VNET_LE;
+ return 0;
+
+ case TUNGETVNETBE:
+ return tun_get_vnet_be(*flags, sp);
+
+ case TUNSETVNETBE:
+ return tun_set_vnet_be(flags, sp);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static inline int tun_vnet_hdr_get(int sz, unsigned int flags,
+ struct iov_iter *from,
+ struct virtio_net_hdr *hdr)
+{
+ u16 hdr_len;
+
+ if (iov_iter_count(from) < sz)
+ return -EINVAL;
+
+ if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
+ return -EFAULT;
+
+ hdr_len = tun_vnet16_to_cpu(flags, hdr->hdr_len);
+
+ if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+ hdr_len = max(tun_vnet16_to_cpu(flags, hdr->csum_start) + tun_vnet16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
+ hdr->hdr_len = cpu_to_tun_vnet16(flags, hdr_len);
+ }
+
+ if (hdr_len > iov_iter_count(from))
+ return -EINVAL;
+
+ iov_iter_advance(from, sz - sizeof(*hdr));
+
+ return hdr_len;
+}
+
+static inline int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
+ const struct virtio_net_hdr *hdr)
+{
+ if (unlikely(iov_iter_count(iter) < sz))
+ return -EINVAL;
+
+ if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
+ return -EFAULT;
+
+ iov_iter_advance(iter, sz - sizeof(*hdr));
+
+ return 0;
+}
+
+static inline int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
+ const struct virtio_net_hdr *hdr)
+{
+ return virtio_net_hdr_to_skb(skb, hdr, tun_vnet_is_little_endian(flags));
+}
+
+static inline int tun_vnet_hdr_from_skb(unsigned int flags,
+ const struct net_device *dev,
+ const struct sk_buff *skb,
+ struct virtio_net_hdr *hdr)
+{
+ int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
+
+ if (virtio_net_hdr_from_skb(skb, hdr,
+ tun_vnet_is_little_endian(flags), true,
+ vlan_hlen)) {
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+ if (net_ratelimit()) {
+ netdev_err(dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
+ sinfo->gso_type, tun_vnet16_to_cpu(flags, hdr->gso_size),
+ tun_vnet16_to_cpu(flags, hdr->hdr_len));
+ print_hex_dump(KERN_ERR, "tun: ",
+ DUMP_PREFIX_NONE,
+ 16, 1, skb->head,
+ min(tun_vnet16_to_cpu(flags, hdr->hdr_len), 64), true);
+ }
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#endif /* TUN_VNET_H */
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user()
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
` (4 preceding siblings ...)
2025-02-05 6:22 ` [PATCH net-next v5 5/7] tun: Extract the vnet handling code Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 21:12 ` Willem de Bruijn
2025-02-05 21:21 ` Willem de Bruijn
2025-02-05 6:22 ` [PATCH net-next v5 7/7] tap: Use tun's vnet-related code Akihiko Odaki
6 siblings, 2 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
hdr_len is repeatedly used so keep it in a local variable.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
drivers/net/tap.c | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 5aa41d5f7765a6dcf185bccd3cba2299bad89398..c55c432bac48d395aebc9ceeaa74f7d07e25af4c 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -645,6 +645,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
int err;
struct virtio_net_hdr vnet_hdr = { 0 };
int vnet_hdr_len = 0;
+ int hdr_len = 0;
int copylen = 0;
int depth;
bool zerocopy = false;
@@ -663,13 +664,13 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from))
goto err;
iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
- if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- tap16_to_cpu(q, vnet_hdr.csum_start) +
- tap16_to_cpu(q, vnet_hdr.csum_offset) + 2 >
- tap16_to_cpu(q, vnet_hdr.hdr_len))
- vnet_hdr.hdr_len = cpu_to_tap16(q,
- tap16_to_cpu(q, vnet_hdr.csum_start) +
- tap16_to_cpu(q, vnet_hdr.csum_offset) + 2);
+ 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;
@@ -682,11 +683,8 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
struct iov_iter i;
- copylen = vnet_hdr.hdr_len ?
- tap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
- if (copylen > good_linear)
- copylen = good_linear;
- else if (copylen < ETH_HLEN)
+ copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear);
+ if (copylen < ETH_HLEN)
copylen = ETH_HLEN;
linear = copylen;
i = *from;
@@ -697,11 +695,9 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (!zerocopy) {
copylen = len;
- linear = tap16_to_cpu(q, vnet_hdr.hdr_len);
- if (linear > good_linear)
- linear = good_linear;
- else if (linear < ETH_HLEN)
- linear = ETH_HLEN;
+ linear = min(hdr_len, good_linear);
+ if (copylen < ETH_HLEN)
+ copylen = ETH_HLEN;
}
skb = tap_alloc_skb(&q->sk, TAP_RESERVE, copylen,
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 7/7] tap: Use tun's vnet-related code
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
` (5 preceding siblings ...)
2025-02-05 6:22 ` [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user() Akihiko Odaki
@ 2025-02-05 6:22 ` Akihiko Odaki
2025-02-05 21:14 ` Willem de Bruijn
6 siblings, 1 reply; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-05 6:22 UTC (permalink / raw)
To: Jonathan Corbet, Willem de Bruijn, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel,
Akihiko Odaki
tun and tap implements the same vnet-related features so reuse the code.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
drivers/net/tap.c | 152 ++++++------------------------------------------------
1 file changed, 16 insertions(+), 136 deletions(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index c55c432bac48d395aebc9ceeaa74f7d07e25af4c..40b077aa639be03cf5a6e9a85734833b289f6b86 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -26,74 +26,9 @@
#include <linux/virtio_net.h>
#include <linux/skb_array.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);
-}
+#include "tun_vnet.h"
-static inline __virtio16 cpu_to_tap16(struct tap_queue *q, u16 val)
-{
- return __cpu_to_virtio16(tap_is_little_endian(q), val);
-}
+#define TAP_IFFEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE)
static struct proto tap_proto = {
.name = "tap",
@@ -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;
@@ -729,8 +652,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;
@@ -793,23 +715,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();
- if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
- sizeof(vnet_hdr))
- return -EFAULT;
+ ret = tun_vnet_hdr_from_skb(q->flags, NULL, skb, &vnet_hdr);
+ if (ret)
+ return ret;
- 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;
@@ -1068,42 +984,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 |
@@ -1147,7 +1027,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);
}
}
@@ -1194,7 +1074,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;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE
2025-02-05 6:22 ` [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE Akihiko Odaki
@ 2025-02-05 21:06 ` Willem de Bruijn
2025-02-06 6:53 ` Akihiko Odaki
0 siblings, 1 reply; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-05 21:06 UTC (permalink / raw)
To: Akihiko Odaki, Jonathan Corbet, Willem de Bruijn, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel, Akihiko Odaki
Cc: Willem de Bruijn
Akihiko Odaki wrote:
> Check IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) to save some lines and make
> future changes easier.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> Reviewed-by: Willem de Bruijn <willemb@google.com>
> ---
> drivers/net/tun.c | 26 ++++++++------------------
> 1 file changed, 8 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index e816aaba8e5f2ed06f8832f79553b6c976e75bb8..452fc5104260fe7ff5fdd5cedc5d2647cbe35c79 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -298,10 +298,10 @@ static bool tun_napi_frags_enabled(const struct tun_file *tfile)
> return tfile->napi_frags_enabled;
> }
>
> -#ifdef CONFIG_TUN_VNET_CROSS_LE
> static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
> {
> - return tun->flags & TUN_VNET_BE ? false :
> + return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
> + (tun->flags & TUN_VNET_BE)) &&
> virtio_legacy_is_little_endian();
Since I have other comments to the series:
Can we make this a bit simpler to the reader, by splitting the test:
if (IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) && tun->flags & TUN_VNET_BE)
return false;
return virtio_legacy_is_little_endian();
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 5/7] tun: Extract the vnet handling code
2025-02-05 6:22 ` [PATCH net-next v5 5/7] tun: Extract the vnet handling code Akihiko Odaki
@ 2025-02-05 21:12 ` Willem de Bruijn
2025-02-06 6:58 ` Akihiko Odaki
0 siblings, 1 reply; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-05 21:12 UTC (permalink / raw)
To: Akihiko Odaki, Jonathan Corbet, Willem de Bruijn, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel, Akihiko Odaki
Akihiko Odaki wrote:
> The vnet handling code will be reused by tap.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
> MAINTAINERS | 2 +-
> drivers/net/tun.c | 179 +----------------------------------------------
> drivers/net/tun_vnet.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 187 insertions(+), 178 deletions(-)
> -static inline bool tun_legacy_is_little_endian(unsigned int flags)
> -{
> - return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
> - (flags & TUN_VNET_BE)) &&
> - virtio_legacy_is_little_endian();
> -}
> +static inline bool tun_vnet_legacy_is_little_endian(unsigned int flags)
> +{
> + return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
> + (flags & TUN_VNET_BE)) &&
> + virtio_legacy_is_little_endian();
> +}
In general LGTM. But why did you rename functions while moving them?
Please add an explanation in the commit message for any non obvious
changes like that.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user()
2025-02-05 6:22 ` [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user() Akihiko Odaki
@ 2025-02-05 21:12 ` Willem de Bruijn
2025-02-05 21:21 ` Willem de Bruijn
1 sibling, 0 replies; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-05 21:12 UTC (permalink / raw)
To: Akihiko Odaki, Jonathan Corbet, Willem de Bruijn, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel, Akihiko Odaki
Akihiko Odaki wrote:
> hdr_len is repeatedly used so keep it in a local variable.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 7/7] tap: Use tun's vnet-related code
2025-02-05 6:22 ` [PATCH net-next v5 7/7] tap: Use tun's vnet-related code Akihiko Odaki
@ 2025-02-05 21:14 ` Willem de Bruijn
0 siblings, 0 replies; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-05 21:14 UTC (permalink / raw)
To: Akihiko Odaki, Jonathan Corbet, Willem de Bruijn, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel, Akihiko Odaki
Akihiko Odaki wrote:
> 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>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user()
2025-02-05 6:22 ` [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user() Akihiko Odaki
2025-02-05 21:12 ` Willem de Bruijn
@ 2025-02-05 21:21 ` Willem de Bruijn
2025-02-06 7:04 ` Akihiko Odaki
1 sibling, 1 reply; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-05 21:21 UTC (permalink / raw)
To: Akihiko Odaki, Jonathan Corbet, Willem de Bruijn, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel, Akihiko Odaki
Akihiko Odaki wrote:
> hdr_len is repeatedly used so keep it in a local variable.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> @@ -682,11 +683,8 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
> if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
> struct iov_iter i;
>
> - copylen = vnet_hdr.hdr_len ?
> - tap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
> - if (copylen > good_linear)
> - copylen = good_linear;
> - else if (copylen < ETH_HLEN)
> + copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear);
> + if (copylen < ETH_HLEN)
> copylen = ETH_HLEN;
I forgot earlier: this can also use single line statement
copylen = max(copylen, ETH_HLEN);
And perhaps easiest to follow is
copylen = hdr_len ?: GOODCOPY_LEN;
copylen = min(copylen, good_linear);
copylen = max(copylen, ETH_HLEN);
> linear = copylen;
> i = *from;
> @@ -697,11 +695,9 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
>
> if (!zerocopy) {
> copylen = len;
> - linear = tap16_to_cpu(q, vnet_hdr.hdr_len);
> - if (linear > good_linear)
> - linear = good_linear;
> - else if (linear < ETH_HLEN)
> - linear = ETH_HLEN;
> + linear = min(hdr_len, good_linear);
> + if (copylen < ETH_HLEN)
> + copylen = ETH_HLEN;
Same
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE
2025-02-05 21:06 ` Willem de Bruijn
@ 2025-02-06 6:53 ` Akihiko Odaki
0 siblings, 0 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-06 6:53 UTC (permalink / raw)
To: Willem de Bruijn, Jonathan Corbet, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel
Cc: Willem de Bruijn
On 2025/02/06 6:06, Willem de Bruijn wrote:
> Akihiko Odaki wrote:
>> Check IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) to save some lines and make
>> future changes easier.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Reviewed-by: Willem de Bruijn <willemb@google.com>
>> ---
>> drivers/net/tun.c | 26 ++++++++------------------
>> 1 file changed, 8 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index e816aaba8e5f2ed06f8832f79553b6c976e75bb8..452fc5104260fe7ff5fdd5cedc5d2647cbe35c79 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -298,10 +298,10 @@ static bool tun_napi_frags_enabled(const struct tun_file *tfile)
>> return tfile->napi_frags_enabled;
>> }
>>
>> -#ifdef CONFIG_TUN_VNET_CROSS_LE
>> static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
>> {
>> - return tun->flags & TUN_VNET_BE ? false :
>> + return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
>> + (tun->flags & TUN_VNET_BE)) &&
>> virtio_legacy_is_little_endian();
>
> Since I have other comments to the series:
>
> Can we make this a bit simpler to the reader, by splitting the test:
>
> if (IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) && tun->flags & TUN_VNET_BE)
> return false;
>
> return virtio_legacy_is_little_endian();
>
I kept all in one expression to show how different variables are reduced
into one bool value, but I agree it is too complicated.
I'm adding a new variable to simplify this. The return statement will
look like: return !be && virtio_legacy_is_little_endian();
It means: for tun, whether the legacy format is in little endian will be
determined from the tun-specific big-endian flag and the virtio's common
logic.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 5/7] tun: Extract the vnet handling code
2025-02-05 21:12 ` Willem de Bruijn
@ 2025-02-06 6:58 ` Akihiko Odaki
0 siblings, 0 replies; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-06 6:58 UTC (permalink / raw)
To: Willem de Bruijn, Jonathan Corbet, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel
On 2025/02/06 6:12, Willem de Bruijn wrote:
> Akihiko Odaki wrote:
>> The vnet handling code will be reused by tap.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>> MAINTAINERS | 2 +-
>> drivers/net/tun.c | 179 +----------------------------------------------
>> drivers/net/tun_vnet.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 187 insertions(+), 178 deletions(-)
>
>> -static inline bool tun_legacy_is_little_endian(unsigned int flags)
>> -{
>> - return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
>> - (flags & TUN_VNET_BE)) &&
>> - virtio_legacy_is_little_endian();
>> -}
>
>> +static inline bool tun_vnet_legacy_is_little_endian(unsigned int flags)
>> +{
>> + return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
>> + (flags & TUN_VNET_BE)) &&
>> + virtio_legacy_is_little_endian();
>> +}
>
> In general LGTM. But why did you rename functions while moving them?
> Please add an explanation in the commit message for any non obvious
> changes like that.
I renamed them to clarify they are in a distinct, decoupled part of
code. It was obvious in the previous version as they are static
functions contained in a translation unit, but now they are part of a
header file so I'm clarifying that with this rename. I will add this
explanation to the commit message.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user()
2025-02-05 21:21 ` Willem de Bruijn
@ 2025-02-06 7:04 ` Akihiko Odaki
2025-02-06 16:09 ` Willem de Bruijn
0 siblings, 1 reply; 17+ messages in thread
From: Akihiko Odaki @ 2025-02-06 7:04 UTC (permalink / raw)
To: Willem de Bruijn, Jonathan Corbet, Jason Wang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Michael S. Tsirkin,
Xuan Zhuo, Shuah Khan, linux-doc, linux-kernel, netdev, kvm,
virtualization, linux-kselftest, Yuri Benditovich,
Andrew Melnychenko, Stephen Hemminger, gur.stavi, devel
On 2025/02/06 6:21, Willem de Bruijn wrote:
> Akihiko Odaki wrote:
>> hdr_len is repeatedly used so keep it in a local variable.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>
>> @@ -682,11 +683,8 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
>> if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
>> struct iov_iter i;
>>
>> - copylen = vnet_hdr.hdr_len ?
>> - tap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
>> - if (copylen > good_linear)
>> - copylen = good_linear;
>> - else if (copylen < ETH_HLEN)
>> + copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear);
>> + if (copylen < ETH_HLEN)
>> copylen = ETH_HLEN;
>
> I forgot earlier: this can also use single line statement
>
> copylen = max(copylen, ETH_HLEN);
>
> And perhaps easiest to follow is
>
> copylen = hdr_len ?: GOODCOPY_LEN;
> copylen = min(copylen, good_linear);
> copylen = max(copylen, ETH_HLEN);
I introduced the min() usage as it now neatly fits in a line, but I
found even clamp() fits so I'll use it in the next version:
copylen = clamp(hdr_len ?: GOODCOPY_LEN, ETH_HLEN, good_linear);
Please tell me if you prefer hdr_len ?: GOODCOPY_LEN in a separate line:
copylen = hdr_len ?: GOODCOPY_LEN;
copylen = clamp(copylen, ETH_HLEN, good_linear);
>
>> linear = copylen;
>> i = *from;
>> @@ -697,11 +695,9 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
>>
>> if (!zerocopy) {
>> copylen = len;
>> - linear = tap16_to_cpu(q, vnet_hdr.hdr_len);
>> - if (linear > good_linear)
>> - linear = good_linear;
>> - else if (linear < ETH_HLEN)
>> - linear = ETH_HLEN;
>> + linear = min(hdr_len, good_linear);
>> + if (copylen < ETH_HLEN)
>> + copylen = ETH_HLEN;> > Same
I realized I mistakenly replaced linear with copylen here. Using clamp()
will remove redundant variable references and fix the bug.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user()
2025-02-06 7:04 ` Akihiko Odaki
@ 2025-02-06 16:09 ` Willem de Bruijn
0 siblings, 0 replies; 17+ messages in thread
From: Willem de Bruijn @ 2025-02-06 16:09 UTC (permalink / raw)
To: Akihiko Odaki, Willem de Bruijn, Jonathan Corbet, Jason Wang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, Xuan Zhuo, Shuah Khan, linux-doc,
linux-kernel, netdev, kvm, virtualization, linux-kselftest,
Yuri Benditovich, Andrew Melnychenko, Stephen Hemminger,
gur.stavi, devel
Akihiko Odaki wrote:
> On 2025/02/06 6:21, Willem de Bruijn wrote:
> > Akihiko Odaki wrote:
> >> hdr_len is repeatedly used so keep it in a local variable.
> >>
> >> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> >
> >> @@ -682,11 +683,8 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
> >> if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
> >> struct iov_iter i;
> >>
> >> - copylen = vnet_hdr.hdr_len ?
> >> - tap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
> >> - if (copylen > good_linear)
> >> - copylen = good_linear;
> >> - else if (copylen < ETH_HLEN)
> >> + copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear);
> >> + if (copylen < ETH_HLEN)
> >> copylen = ETH_HLEN;
> >
> > I forgot earlier: this can also use single line statement
> >
> > copylen = max(copylen, ETH_HLEN);
> >
> > And perhaps easiest to follow is
> >
> > copylen = hdr_len ?: GOODCOPY_LEN;
> > copylen = min(copylen, good_linear);
> > copylen = max(copylen, ETH_HLEN);
>
> I introduced the min() usage as it now neatly fits in a line, but I
> found even clamp() fits so I'll use it in the next version:
> copylen = clamp(hdr_len ?: GOODCOPY_LEN, ETH_HLEN, good_linear);
>
> Please tell me if you prefer hdr_len ?: GOODCOPY_LEN in a separate line:
> copylen = hdr_len ?: GOODCOPY_LEN;
> copylen = clamp(copylen, ETH_HLEN, good_linear);
Oh nice. I had forgotten about clamp. Even better.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-02-06 16:09 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-05 6:22 [PATCH net-next v5 0/7] tun: Unify vnet implementation Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 1/7] tun: Refactor CONFIG_TUN_VNET_CROSS_LE Akihiko Odaki
2025-02-05 21:06 ` Willem de Bruijn
2025-02-06 6:53 ` Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 2/7] tun: Keep hdr_len in tun_get_user() Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 3/7] tun: Decouple vnet from tun_struct Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 4/7] tun: Decouple vnet handling Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 5/7] tun: Extract the vnet handling code Akihiko Odaki
2025-02-05 21:12 ` Willem de Bruijn
2025-02-06 6:58 ` Akihiko Odaki
2025-02-05 6:22 ` [PATCH net-next v5 6/7] tap: Keep hdr_len in tap_get_user() Akihiko Odaki
2025-02-05 21:12 ` Willem de Bruijn
2025-02-05 21:21 ` Willem de Bruijn
2025-02-06 7:04 ` Akihiko Odaki
2025-02-06 16:09 ` Willem de Bruijn
2025-02-05 6:22 ` [PATCH net-next v5 7/7] tap: Use tun's vnet-related code Akihiko Odaki
2025-02-05 21:14 ` Willem de Bruijn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).