diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2014-10-23 15:59:31 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2014-12-09 05:05:31 -0500 |
commit | 56f0dcc5aaeb9f56c40d480b87f9b4161f18ebc5 (patch) | |
tree | 676a1e1660a4e738d7fb4a03135f47f8ba5468ff /drivers/net/tun.c | |
parent | e999d6ea2a4f313a5bba514b08f6f01b0c0072a9 (diff) |
tun: TUN_VNET_LE support, fix sparse warnings for virtio headers
Pretty straight-forward: convert all fields to/from
virtio endian-ness.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Jason Wang <jasowang@redhat.com>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 36be4fd0cd23..c052bd6b2f23 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -111,7 +111,7 @@ do { \ | |||
111 | #define TUN_FASYNC IFF_ATTACH_QUEUE | 111 | #define TUN_FASYNC IFF_ATTACH_QUEUE |
112 | 112 | ||
113 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ | 113 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ |
114 | IFF_MULTI_QUEUE) | 114 | IFF_VNET_LE | IFF_MULTI_QUEUE) |
115 | #define GOODCOPY_LEN 128 | 115 | #define GOODCOPY_LEN 128 |
116 | 116 | ||
117 | #define FLT_EXACT_COUNT 8 | 117 | #define FLT_EXACT_COUNT 8 |
@@ -205,6 +205,16 @@ struct tun_struct { | |||
205 | u32 flow_count; | 205 | u32 flow_count; |
206 | }; | 206 | }; |
207 | 207 | ||
208 | static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) | ||
209 | { | ||
210 | return __virtio16_to_cpu(tun->flags & IFF_VNET_LE, val); | ||
211 | } | ||
212 | |||
213 | static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) | ||
214 | { | ||
215 | return __cpu_to_virtio16(tun->flags & IFF_VNET_LE, val); | ||
216 | } | ||
217 | |||
208 | static inline u32 tun_hashfn(u32 rxhash) | 218 | static inline u32 tun_hashfn(u32 rxhash) |
209 | { | 219 | { |
210 | return rxhash & 0x3ff; | 220 | return rxhash & 0x3ff; |
@@ -1053,10 +1063,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1053 | return -EFAULT; | 1063 | return -EFAULT; |
1054 | 1064 | ||
1055 | if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && | 1065 | if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && |
1056 | gso.csum_start + gso.csum_offset + 2 > gso.hdr_len) | 1066 | tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len)) |
1057 | gso.hdr_len = gso.csum_start + gso.csum_offset + 2; | 1067 | gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2); |
1058 | 1068 | ||
1059 | if (gso.hdr_len > len) | 1069 | if (tun16_to_cpu(tun, gso.hdr_len) > len) |
1060 | return -EINVAL; | 1070 | return -EINVAL; |
1061 | offset += tun->vnet_hdr_sz; | 1071 | offset += tun->vnet_hdr_sz; |
1062 | } | 1072 | } |
@@ -1064,7 +1074,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1064 | if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { | 1074 | if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { |
1065 | align += NET_IP_ALIGN; | 1075 | align += NET_IP_ALIGN; |
1066 | if (unlikely(len < ETH_HLEN || | 1076 | if (unlikely(len < ETH_HLEN || |
1067 | (gso.hdr_len && gso.hdr_len < ETH_HLEN))) | 1077 | (gso.hdr_len && tun16_to_cpu(tun, gso.hdr_len) < ETH_HLEN))) |
1068 | return -EINVAL; | 1078 | return -EINVAL; |
1069 | } | 1079 | } |
1070 | 1080 | ||
@@ -1075,7 +1085,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1075 | * enough room for skb expand head in case it is used. | 1085 | * enough room for skb expand head in case it is used. |
1076 | * The rest of the buffer is mapped from userspace. | 1086 | * The rest of the buffer is mapped from userspace. |
1077 | */ | 1087 | */ |
1078 | copylen = gso.hdr_len ? gso.hdr_len : GOODCOPY_LEN; | 1088 | copylen = gso.hdr_len ? tun16_to_cpu(tun, gso.hdr_len) : GOODCOPY_LEN; |
1079 | if (copylen > good_linear) | 1089 | if (copylen > good_linear) |
1080 | copylen = good_linear; | 1090 | copylen = good_linear; |
1081 | linear = copylen; | 1091 | linear = copylen; |
@@ -1085,10 +1095,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1085 | 1095 | ||
1086 | if (!zerocopy) { | 1096 | if (!zerocopy) { |
1087 | copylen = len; | 1097 | copylen = len; |
1088 | if (gso.hdr_len > good_linear) | 1098 | if (tun16_to_cpu(tun, gso.hdr_len) > good_linear) |
1089 | linear = good_linear; | 1099 | linear = good_linear; |
1090 | else | 1100 | else |
1091 | linear = gso.hdr_len; | 1101 | linear = tun16_to_cpu(tun, gso.hdr_len); |
1092 | } | 1102 | } |
1093 | 1103 | ||
1094 | skb = tun_alloc_skb(tfile, align, copylen, linear, noblock); | 1104 | skb = tun_alloc_skb(tfile, align, copylen, linear, noblock); |
@@ -1115,8 +1125,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1115 | } | 1125 | } |
1116 | 1126 | ||
1117 | if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { | 1127 | if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { |
1118 | if (!skb_partial_csum_set(skb, gso.csum_start, | 1128 | if (!skb_partial_csum_set(skb, tun16_to_cpu(tun, gso.csum_start), |
1119 | gso.csum_offset)) { | 1129 | tun16_to_cpu(tun, gso.csum_offset))) { |
1120 | tun->dev->stats.rx_frame_errors++; | 1130 | tun->dev->stats.rx_frame_errors++; |
1121 | kfree_skb(skb); | 1131 | kfree_skb(skb); |
1122 | return -EINVAL; | 1132 | return -EINVAL; |
@@ -1184,7 +1194,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1184 | if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN) | 1194 | if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN) |
1185 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; | 1195 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; |
1186 | 1196 | ||
1187 | skb_shinfo(skb)->gso_size = gso.gso_size; | 1197 | skb_shinfo(skb)->gso_size = tun16_to_cpu(tun, gso.gso_size); |
1188 | if (skb_shinfo(skb)->gso_size == 0) { | 1198 | if (skb_shinfo(skb)->gso_size == 0) { |
1189 | tun->dev->stats.rx_frame_errors++; | 1199 | tun->dev->stats.rx_frame_errors++; |
1190 | kfree_skb(skb); | 1200 | kfree_skb(skb); |
@@ -1276,8 +1286,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1276 | struct skb_shared_info *sinfo = skb_shinfo(skb); | 1286 | struct skb_shared_info *sinfo = skb_shinfo(skb); |
1277 | 1287 | ||
1278 | /* This is a hint as to how much should be linear. */ | 1288 | /* This is a hint as to how much should be linear. */ |
1279 | gso.hdr_len = skb_headlen(skb); | 1289 | gso.hdr_len = cpu_to_tun16(tun, skb_headlen(skb)); |
1280 | gso.gso_size = sinfo->gso_size; | 1290 | gso.gso_size = cpu_to_tun16(tun, sinfo->gso_size); |
1281 | if (sinfo->gso_type & SKB_GSO_TCPV4) | 1291 | if (sinfo->gso_type & SKB_GSO_TCPV4) |
1282 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; | 1292 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; |
1283 | else if (sinfo->gso_type & SKB_GSO_TCPV6) | 1293 | else if (sinfo->gso_type & SKB_GSO_TCPV6) |
@@ -1285,12 +1295,12 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1285 | else { | 1295 | else { |
1286 | pr_err("unexpected GSO type: " | 1296 | pr_err("unexpected GSO type: " |
1287 | "0x%x, gso_size %d, hdr_len %d\n", | 1297 | "0x%x, gso_size %d, hdr_len %d\n", |
1288 | sinfo->gso_type, gso.gso_size, | 1298 | sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size), |
1289 | gso.hdr_len); | 1299 | tun16_to_cpu(tun, gso.hdr_len)); |
1290 | print_hex_dump(KERN_ERR, "tun: ", | 1300 | print_hex_dump(KERN_ERR, "tun: ", |
1291 | DUMP_PREFIX_NONE, | 1301 | DUMP_PREFIX_NONE, |
1292 | 16, 1, skb->head, | 1302 | 16, 1, skb->head, |
1293 | min((int)gso.hdr_len, 64), true); | 1303 | min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true); |
1294 | WARN_ON_ONCE(1); | 1304 | WARN_ON_ONCE(1); |
1295 | return -EINVAL; | 1305 | return -EINVAL; |
1296 | } | 1306 | } |
@@ -1301,9 +1311,9 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1301 | 1311 | ||
1302 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1312 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1303 | gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; | 1313 | gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; |
1304 | gso.csum_start = skb_checksum_start_offset(skb) + | 1314 | gso.csum_start = cpu_to_tun16(tun, skb_checksum_start_offset(skb) + |
1305 | vlan_hlen; | 1315 | vlan_hlen); |
1306 | gso.csum_offset = skb->csum_offset; | 1316 | gso.csum_offset = cpu_to_tun16(tun, skb->csum_offset); |
1307 | } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { | 1317 | } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { |
1308 | gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; | 1318 | gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; |
1309 | } /* else everything is zero */ | 1319 | } /* else everything is zero */ |