diff options
-rw-r--r-- | drivers/net/virtio_net.c | 81 |
1 files changed, 44 insertions, 37 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 3041e4eddb3b..420388a4c5e8 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -68,9 +68,16 @@ struct virtnet_info | |||
68 | struct page *pages; | 68 | struct page *pages; |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static inline void *skb_vnet_hdr(struct sk_buff *skb) | 71 | struct skb_vnet_hdr { |
72 | union { | ||
73 | struct virtio_net_hdr hdr; | ||
74 | struct virtio_net_hdr_mrg_rxbuf mhdr; | ||
75 | }; | ||
76 | }; | ||
77 | |||
78 | static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb) | ||
72 | { | 79 | { |
73 | return (struct virtio_net_hdr *)skb->cb; | 80 | return (struct skb_vnet_hdr *)skb->cb; |
74 | } | 81 | } |
75 | 82 | ||
76 | static void give_a_page(struct virtnet_info *vi, struct page *page) | 83 | static void give_a_page(struct virtnet_info *vi, struct page *page) |
@@ -115,7 +122,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
115 | unsigned len) | 122 | unsigned len) |
116 | { | 123 | { |
117 | struct virtnet_info *vi = netdev_priv(dev); | 124 | struct virtnet_info *vi = netdev_priv(dev); |
118 | struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); | 125 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); |
119 | int err; | 126 | int err; |
120 | int i; | 127 | int i; |
121 | 128 | ||
@@ -126,7 +133,6 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
126 | } | 133 | } |
127 | 134 | ||
128 | if (vi->mergeable_rx_bufs) { | 135 | if (vi->mergeable_rx_bufs) { |
129 | struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); | ||
130 | unsigned int copy; | 136 | unsigned int copy; |
131 | char *p = page_address(skb_shinfo(skb)->frags[0].page); | 137 | char *p = page_address(skb_shinfo(skb)->frags[0].page); |
132 | 138 | ||
@@ -134,8 +140,8 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
134 | len = PAGE_SIZE; | 140 | len = PAGE_SIZE; |
135 | len -= sizeof(struct virtio_net_hdr_mrg_rxbuf); | 141 | len -= sizeof(struct virtio_net_hdr_mrg_rxbuf); |
136 | 142 | ||
137 | memcpy(hdr, p, sizeof(*mhdr)); | 143 | memcpy(&hdr->mhdr, p, sizeof(hdr->mhdr)); |
138 | p += sizeof(*mhdr); | 144 | p += sizeof(hdr->mhdr); |
139 | 145 | ||
140 | copy = len; | 146 | copy = len; |
141 | if (copy > skb_tailroom(skb)) | 147 | if (copy > skb_tailroom(skb)) |
@@ -150,13 +156,13 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
150 | skb_shinfo(skb)->nr_frags--; | 156 | skb_shinfo(skb)->nr_frags--; |
151 | } else { | 157 | } else { |
152 | skb_shinfo(skb)->frags[0].page_offset += | 158 | skb_shinfo(skb)->frags[0].page_offset += |
153 | sizeof(*mhdr) + copy; | 159 | sizeof(hdr->mhdr) + copy; |
154 | skb_shinfo(skb)->frags[0].size = len; | 160 | skb_shinfo(skb)->frags[0].size = len; |
155 | skb->data_len += len; | 161 | skb->data_len += len; |
156 | skb->len += len; | 162 | skb->len += len; |
157 | } | 163 | } |
158 | 164 | ||
159 | while (--mhdr->num_buffers) { | 165 | while (--hdr->mhdr.num_buffers) { |
160 | struct sk_buff *nskb; | 166 | struct sk_buff *nskb; |
161 | 167 | ||
162 | i = skb_shinfo(skb)->nr_frags; | 168 | i = skb_shinfo(skb)->nr_frags; |
@@ -170,7 +176,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
170 | nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len); | 176 | nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len); |
171 | if (!nskb) { | 177 | if (!nskb) { |
172 | pr_debug("%s: rx error: %d buffers missing\n", | 178 | pr_debug("%s: rx error: %d buffers missing\n", |
173 | dev->name, mhdr->num_buffers); | 179 | dev->name, hdr->mhdr.num_buffers); |
174 | dev->stats.rx_length_errors++; | 180 | dev->stats.rx_length_errors++; |
175 | goto drop; | 181 | goto drop; |
176 | } | 182 | } |
@@ -191,7 +197,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
191 | skb->len += len; | 197 | skb->len += len; |
192 | } | 198 | } |
193 | } else { | 199 | } else { |
194 | len -= sizeof(struct virtio_net_hdr); | 200 | len -= sizeof(hdr->hdr); |
195 | 201 | ||
196 | if (len <= MAX_PACKET_LEN) | 202 | if (len <= MAX_PACKET_LEN) |
197 | trim_pages(vi, skb); | 203 | trim_pages(vi, skb); |
@@ -209,9 +215,11 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
209 | dev->stats.rx_bytes += skb->len; | 215 | dev->stats.rx_bytes += skb->len; |
210 | dev->stats.rx_packets++; | 216 | dev->stats.rx_packets++; |
211 | 217 | ||
212 | if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { | 218 | if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { |
213 | pr_debug("Needs csum!\n"); | 219 | pr_debug("Needs csum!\n"); |
214 | if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset)) | 220 | if (!skb_partial_csum_set(skb, |
221 | hdr->hdr.csum_start, | ||
222 | hdr->hdr.csum_offset)) | ||
215 | goto frame_err; | 223 | goto frame_err; |
216 | } | 224 | } |
217 | 225 | ||
@@ -219,9 +227,9 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
219 | pr_debug("Receiving skb proto 0x%04x len %i type %i\n", | 227 | pr_debug("Receiving skb proto 0x%04x len %i type %i\n", |
220 | ntohs(skb->protocol), skb->len, skb->pkt_type); | 228 | ntohs(skb->protocol), skb->len, skb->pkt_type); |
221 | 229 | ||
222 | if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { | 230 | if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) { |
223 | pr_debug("GSO!\n"); | 231 | pr_debug("GSO!\n"); |
224 | switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { | 232 | switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { |
225 | case VIRTIO_NET_HDR_GSO_TCPV4: | 233 | case VIRTIO_NET_HDR_GSO_TCPV4: |
226 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | 234 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; |
227 | break; | 235 | break; |
@@ -234,14 +242,14 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
234 | default: | 242 | default: |
235 | if (net_ratelimit()) | 243 | if (net_ratelimit()) |
236 | printk(KERN_WARNING "%s: bad gso type %u.\n", | 244 | printk(KERN_WARNING "%s: bad gso type %u.\n", |
237 | dev->name, hdr->gso_type); | 245 | dev->name, hdr->hdr.gso_type); |
238 | goto frame_err; | 246 | goto frame_err; |
239 | } | 247 | } |
240 | 248 | ||
241 | if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) | 249 | if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN) |
242 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; | 250 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; |
243 | 251 | ||
244 | skb_shinfo(skb)->gso_size = hdr->gso_size; | 252 | skb_shinfo(skb)->gso_size = hdr->hdr.gso_size; |
245 | if (skb_shinfo(skb)->gso_size == 0) { | 253 | if (skb_shinfo(skb)->gso_size == 0) { |
246 | if (net_ratelimit()) | 254 | if (net_ratelimit()) |
247 | printk(KERN_WARNING "%s: zero gso size.\n", | 255 | printk(KERN_WARNING "%s: zero gso size.\n", |
@@ -272,7 +280,7 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp) | |||
272 | 280 | ||
273 | sg_init_table(sg, 2+MAX_SKB_FRAGS); | 281 | sg_init_table(sg, 2+MAX_SKB_FRAGS); |
274 | for (;;) { | 282 | for (;;) { |
275 | struct virtio_net_hdr *hdr; | 283 | struct skb_vnet_hdr *hdr; |
276 | 284 | ||
277 | skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN); | 285 | skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN); |
278 | if (unlikely(!skb)) { | 286 | if (unlikely(!skb)) { |
@@ -284,7 +292,7 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp) | |||
284 | skb_put(skb, MAX_PACKET_LEN); | 292 | skb_put(skb, MAX_PACKET_LEN); |
285 | 293 | ||
286 | hdr = skb_vnet_hdr(skb); | 294 | hdr = skb_vnet_hdr(skb); |
287 | sg_set_buf(sg, hdr, sizeof(*hdr)); | 295 | sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); |
288 | 296 | ||
289 | if (vi->big_packets) { | 297 | if (vi->big_packets) { |
290 | for (i = 0; i < MAX_SKB_FRAGS; i++) { | 298 | for (i = 0; i < MAX_SKB_FRAGS; i++) { |
@@ -452,8 +460,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
452 | { | 460 | { |
453 | int num; | 461 | int num; |
454 | struct scatterlist sg[2+MAX_SKB_FRAGS]; | 462 | struct scatterlist sg[2+MAX_SKB_FRAGS]; |
455 | struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); | 463 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); |
456 | struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); | ||
457 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | 464 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; |
458 | 465 | ||
459 | sg_init_table(sg, 2+MAX_SKB_FRAGS); | 466 | sg_init_table(sg, 2+MAX_SKB_FRAGS); |
@@ -461,39 +468,39 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
461 | pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); | 468 | pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); |
462 | 469 | ||
463 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 470 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
464 | hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; | 471 | hdr->hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; |
465 | hdr->csum_start = skb->csum_start - skb_headroom(skb); | 472 | hdr->hdr.csum_start = skb->csum_start - skb_headroom(skb); |
466 | hdr->csum_offset = skb->csum_offset; | 473 | hdr->hdr.csum_offset = skb->csum_offset; |
467 | } else { | 474 | } else { |
468 | hdr->flags = 0; | 475 | hdr->hdr.flags = 0; |
469 | hdr->csum_offset = hdr->csum_start = 0; | 476 | hdr->hdr.csum_offset = hdr->hdr.csum_start = 0; |
470 | } | 477 | } |
471 | 478 | ||
472 | if (skb_is_gso(skb)) { | 479 | if (skb_is_gso(skb)) { |
473 | hdr->hdr_len = skb_headlen(skb); | 480 | hdr->hdr.hdr_len = skb_headlen(skb); |
474 | hdr->gso_size = skb_shinfo(skb)->gso_size; | 481 | hdr->hdr.gso_size = skb_shinfo(skb)->gso_size; |
475 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) | 482 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) |
476 | hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; | 483 | hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; |
477 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | 484 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) |
478 | hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; | 485 | hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; |
479 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) | 486 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) |
480 | hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; | 487 | hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP; |
481 | else | 488 | else |
482 | BUG(); | 489 | BUG(); |
483 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) | 490 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) |
484 | hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; | 491 | hdr->hdr.gso_type |= VIRTIO_NET_HDR_GSO_ECN; |
485 | } else { | 492 | } else { |
486 | hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; | 493 | hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE; |
487 | hdr->gso_size = hdr->hdr_len = 0; | 494 | hdr->hdr.gso_size = hdr->hdr.hdr_len = 0; |
488 | } | 495 | } |
489 | 496 | ||
490 | mhdr->num_buffers = 0; | 497 | hdr->mhdr.num_buffers = 0; |
491 | 498 | ||
492 | /* Encode metadata header at front. */ | 499 | /* Encode metadata header at front. */ |
493 | if (vi->mergeable_rx_bufs) | 500 | if (vi->mergeable_rx_bufs) |
494 | sg_set_buf(sg, mhdr, sizeof(*mhdr)); | 501 | sg_set_buf(sg, &hdr->mhdr, sizeof(hdr->mhdr)); |
495 | else | 502 | else |
496 | sg_set_buf(sg, hdr, sizeof(*hdr)); | 503 | sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); |
497 | 504 | ||
498 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; | 505 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; |
499 | return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); | 506 | return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); |