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); |
