diff options
author | Greg Kurz <gkurz@linux.vnet.ibm.com> | 2015-04-24 08:50:36 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2015-06-01 09:48:56 -0400 |
commit | 8b8e658b16336f0f50aba733f51db636ef121f50 (patch) | |
tree | 07e2259234babcd1c2f535ff43e1bede107f74d2 /drivers/net/tun.c | |
parent | 2751c9882b947292fcfb084c4f604e01724af804 (diff) |
macvtap/tun: cross-endian support for little-endian hosts
The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers
that are always little-endian. It can also be used to handle the special
case of a legacy little-endian device implemented by a big-endian host.
Let's add a flag and ioctls for big-endian devices as well. If both flags
are set, little-endian wins.
Since this is isn't a common usecase, the feature is controlled by a kernel
config option (not set by default).
Both macvtap and tun are covered by this patch since they share the same
API with userland.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b210139bef8f..cb376b2d548a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -111,6 +111,7 @@ do { \ | |||
111 | #define TUN_FASYNC IFF_ATTACH_QUEUE | 111 | #define TUN_FASYNC IFF_ATTACH_QUEUE |
112 | /* High bits in flags field are unused. */ | 112 | /* High bits in flags field are unused. */ |
113 | #define TUN_VNET_LE 0x80000000 | 113 | #define TUN_VNET_LE 0x80000000 |
114 | #define TUN_VNET_BE 0x40000000 | ||
114 | 115 | ||
115 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ | 116 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ |
116 | IFF_MULTI_QUEUE) | 117 | IFF_MULTI_QUEUE) |
@@ -206,10 +207,58 @@ struct tun_struct { | |||
206 | u32 flow_count; | 207 | u32 flow_count; |
207 | }; | 208 | }; |
208 | 209 | ||
210 | #ifdef CONFIG_TUN_VNET_CROSS_LE | ||
211 | static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) | ||
212 | { | ||
213 | return tun->flags & TUN_VNET_BE ? false : | ||
214 | virtio_legacy_is_little_endian(); | ||
215 | } | ||
216 | |||
217 | static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) | ||
218 | { | ||
219 | int be = !!(tun->flags & TUN_VNET_BE); | ||
220 | |||
221 | if (put_user(be, argp)) | ||
222 | return -EFAULT; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) | ||
228 | { | ||
229 | int be; | ||
230 | |||
231 | if (get_user(be, argp)) | ||
232 | return -EFAULT; | ||
233 | |||
234 | if (be) | ||
235 | tun->flags |= TUN_VNET_BE; | ||
236 | else | ||
237 | tun->flags &= ~TUN_VNET_BE; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | #else | ||
242 | static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) | ||
243 | { | ||
244 | return virtio_legacy_is_little_endian(); | ||
245 | } | ||
246 | |||
247 | static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) | ||
248 | { | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) | ||
253 | { | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | #endif /* CONFIG_TUN_VNET_CROSS_LE */ | ||
257 | |||
209 | static inline bool tun_is_little_endian(struct tun_struct *tun) | 258 | static inline bool tun_is_little_endian(struct tun_struct *tun) |
210 | { | 259 | { |
211 | return tun->flags & TUN_VNET_LE || | 260 | return tun->flags & TUN_VNET_LE || |
212 | virtio_legacy_is_little_endian(); | 261 | tun_legacy_is_little_endian(tun); |
213 | } | 262 | } |
214 | 263 | ||
215 | static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) | 264 | static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) |
@@ -2062,6 +2111,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
2062 | tun->flags &= ~TUN_VNET_LE; | 2111 | tun->flags &= ~TUN_VNET_LE; |
2063 | break; | 2112 | break; |
2064 | 2113 | ||
2114 | case TUNGETVNETBE: | ||
2115 | ret = tun_get_vnet_be(tun, argp); | ||
2116 | break; | ||
2117 | |||
2118 | case TUNSETVNETBE: | ||
2119 | ret = tun_set_vnet_be(tun, argp); | ||
2120 | break; | ||
2121 | |||
2065 | case TUNATTACHFILTER: | 2122 | case TUNATTACHFILTER: |
2066 | /* Can be set only for TAPs */ | 2123 | /* Can be set only for TAPs */ |
2067 | ret = -EINVAL; | 2124 | ret = -EINVAL; |