diff options
Diffstat (limited to 'drivers/net/xen-netback')
| -rw-r--r-- | drivers/net/xen-netback/common.h | 32 | ||||
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 54 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 392 | ||||
| -rw-r--r-- | drivers/net/xen-netback/xenbus.c | 52 |
4 files changed, 423 insertions, 107 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5715318d6bab..c47794b9d42f 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
| @@ -87,9 +87,13 @@ struct pending_tx_info { | |||
| 87 | struct xenvif_rx_meta { | 87 | struct xenvif_rx_meta { |
| 88 | int id; | 88 | int id; |
| 89 | int size; | 89 | int size; |
| 90 | int gso_type; | ||
| 90 | int gso_size; | 91 | int gso_size; |
| 91 | }; | 92 | }; |
| 92 | 93 | ||
| 94 | #define GSO_BIT(type) \ | ||
| 95 | (1 << XEN_NETIF_GSO_TYPE_ ## type) | ||
| 96 | |||
| 93 | /* Discriminate from any valid pending_idx value. */ | 97 | /* Discriminate from any valid pending_idx value. */ |
| 94 | #define INVALID_PENDING_IDX 0xFFFF | 98 | #define INVALID_PENDING_IDX 0xFFFF |
| 95 | 99 | ||
| @@ -97,6 +101,13 @@ struct xenvif_rx_meta { | |||
| 97 | 101 | ||
| 98 | #define MAX_PENDING_REQS 256 | 102 | #define MAX_PENDING_REQS 256 |
| 99 | 103 | ||
| 104 | /* It's possible for an skb to have a maximal number of frags | ||
| 105 | * but still be less than MAX_BUFFER_OFFSET in size. Thus the | ||
| 106 | * worst-case number of copy operations is MAX_SKB_FRAGS per | ||
| 107 | * ring slot. | ||
| 108 | */ | ||
| 109 | #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) | ||
| 110 | |||
| 100 | struct xenvif { | 111 | struct xenvif { |
| 101 | /* Unique identifier for this interface. */ | 112 | /* Unique identifier for this interface. */ |
| 102 | domid_t domid; | 113 | domid_t domid; |
| @@ -139,21 +150,23 @@ struct xenvif { | |||
| 139 | */ | 150 | */ |
| 140 | RING_IDX rx_req_cons_peek; | 151 | RING_IDX rx_req_cons_peek; |
| 141 | 152 | ||
| 142 | /* Given MAX_BUFFER_OFFSET of 4096 the worst case is that each | 153 | /* This array is allocated seperately as it is large */ |
| 143 | * head/fragment page uses 2 copy operations because it | 154 | struct gnttab_copy *grant_copy_op; |
| 144 | * straddles two buffers in the frontend. | ||
| 145 | */ | ||
| 146 | struct gnttab_copy grant_copy_op[2*XEN_NETIF_RX_RING_SIZE]; | ||
| 147 | struct xenvif_rx_meta meta[2*XEN_NETIF_RX_RING_SIZE]; | ||
| 148 | 155 | ||
| 156 | /* We create one meta structure per ring request we consume, so | ||
| 157 | * the maximum number is the same as the ring size. | ||
| 158 | */ | ||
| 159 | struct xenvif_rx_meta meta[XEN_NETIF_RX_RING_SIZE]; | ||
| 149 | 160 | ||
| 150 | u8 fe_dev_addr[6]; | 161 | u8 fe_dev_addr[6]; |
| 151 | 162 | ||
| 152 | /* Frontend feature information. */ | 163 | /* Frontend feature information. */ |
| 164 | int gso_mask; | ||
| 165 | int gso_prefix_mask; | ||
| 166 | |||
| 153 | u8 can_sg:1; | 167 | u8 can_sg:1; |
| 154 | u8 gso:1; | 168 | u8 ip_csum:1; |
| 155 | u8 gso_prefix:1; | 169 | u8 ipv6_csum:1; |
| 156 | u8 csum:1; | ||
| 157 | 170 | ||
| 158 | /* Internal feature information. */ | 171 | /* Internal feature information. */ |
| 159 | u8 can_queue:1; /* can queue packets for receiver? */ | 172 | u8 can_queue:1; /* can queue packets for receiver? */ |
| @@ -163,6 +176,7 @@ struct xenvif { | |||
| 163 | unsigned long credit_usec; | 176 | unsigned long credit_usec; |
| 164 | unsigned long remaining_credit; | 177 | unsigned long remaining_credit; |
| 165 | struct timer_list credit_timeout; | 178 | struct timer_list credit_timeout; |
| 179 | u64 credit_window_start; | ||
| 166 | 180 | ||
| 167 | /* Statistics */ | 181 | /* Statistics */ |
| 168 | unsigned long rx_gso_checksum_fixup; | 182 | unsigned long rx_gso_checksum_fixup; |
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 01bb854c7f62..fff8cddfed81 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
| 35 | #include <linux/rtnetlink.h> | 35 | #include <linux/rtnetlink.h> |
| 36 | #include <linux/if_vlan.h> | 36 | #include <linux/if_vlan.h> |
| 37 | #include <linux/vmalloc.h> | ||
| 37 | 38 | ||
| 38 | #include <xen/events.h> | 39 | #include <xen/events.h> |
| 39 | #include <asm/xen/hypercall.h> | 40 | #include <asm/xen/hypercall.h> |
| @@ -214,10 +215,14 @@ static netdev_features_t xenvif_fix_features(struct net_device *dev, | |||
| 214 | 215 | ||
| 215 | if (!vif->can_sg) | 216 | if (!vif->can_sg) |
| 216 | features &= ~NETIF_F_SG; | 217 | features &= ~NETIF_F_SG; |
| 217 | if (!vif->gso && !vif->gso_prefix) | 218 | if (~(vif->gso_mask | vif->gso_prefix_mask) & GSO_BIT(TCPV4)) |
| 218 | features &= ~NETIF_F_TSO; | 219 | features &= ~NETIF_F_TSO; |
| 219 | if (!vif->csum) | 220 | if (~(vif->gso_mask | vif->gso_prefix_mask) & GSO_BIT(TCPV6)) |
| 221 | features &= ~NETIF_F_TSO6; | ||
| 222 | if (!vif->ip_csum) | ||
| 220 | features &= ~NETIF_F_IP_CSUM; | 223 | features &= ~NETIF_F_IP_CSUM; |
| 224 | if (!vif->ipv6_csum) | ||
| 225 | features &= ~NETIF_F_IPV6_CSUM; | ||
| 221 | 226 | ||
| 222 | return features; | 227 | return features; |
| 223 | } | 228 | } |
| @@ -303,21 +308,31 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, | |||
| 303 | SET_NETDEV_DEV(dev, parent); | 308 | SET_NETDEV_DEV(dev, parent); |
| 304 | 309 | ||
| 305 | vif = netdev_priv(dev); | 310 | vif = netdev_priv(dev); |
| 311 | |||
| 312 | vif->grant_copy_op = vmalloc(sizeof(struct gnttab_copy) * | ||
| 313 | MAX_GRANT_COPY_OPS); | ||
| 314 | if (vif->grant_copy_op == NULL) { | ||
| 315 | pr_warn("Could not allocate grant copy space for %s\n", name); | ||
| 316 | free_netdev(dev); | ||
| 317 | return ERR_PTR(-ENOMEM); | ||
| 318 | } | ||
| 319 | |||
| 306 | vif->domid = domid; | 320 | vif->domid = domid; |
| 307 | vif->handle = handle; | 321 | vif->handle = handle; |
| 308 | vif->can_sg = 1; | 322 | vif->can_sg = 1; |
| 309 | vif->csum = 1; | 323 | vif->ip_csum = 1; |
| 310 | vif->dev = dev; | 324 | vif->dev = dev; |
| 311 | 325 | ||
| 312 | vif->credit_bytes = vif->remaining_credit = ~0UL; | 326 | vif->credit_bytes = vif->remaining_credit = ~0UL; |
| 313 | vif->credit_usec = 0UL; | 327 | vif->credit_usec = 0UL; |
| 314 | init_timer(&vif->credit_timeout); | 328 | init_timer(&vif->credit_timeout); |
| 315 | /* Initialize 'expires' now: it's used to track the credit window. */ | 329 | vif->credit_window_start = get_jiffies_64(); |
| 316 | vif->credit_timeout.expires = jiffies; | ||
| 317 | 330 | ||
| 318 | dev->netdev_ops = &xenvif_netdev_ops; | 331 | dev->netdev_ops = &xenvif_netdev_ops; |
| 319 | dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; | 332 | dev->hw_features = NETIF_F_SG | |
| 320 | dev->features = dev->hw_features; | 333 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
| 334 | NETIF_F_TSO | NETIF_F_TSO6; | ||
| 335 | dev->features = dev->hw_features | NETIF_F_RXCSUM; | ||
| 321 | SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); | 336 | SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); |
| 322 | 337 | ||
| 323 | dev->tx_queue_len = XENVIF_QUEUE_LENGTH; | 338 | dev->tx_queue_len = XENVIF_QUEUE_LENGTH; |
| @@ -363,11 +378,11 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
| 363 | unsigned long rx_ring_ref, unsigned int tx_evtchn, | 378 | unsigned long rx_ring_ref, unsigned int tx_evtchn, |
| 364 | unsigned int rx_evtchn) | 379 | unsigned int rx_evtchn) |
| 365 | { | 380 | { |
| 381 | struct task_struct *task; | ||
| 366 | int err = -ENOMEM; | 382 | int err = -ENOMEM; |
| 367 | 383 | ||
| 368 | /* Already connected through? */ | 384 | BUG_ON(vif->tx_irq); |
| 369 | if (vif->tx_irq) | 385 | BUG_ON(vif->task); |
| 370 | return 0; | ||
| 371 | 386 | ||
| 372 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); | 387 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); |
| 373 | if (err < 0) | 388 | if (err < 0) |
| @@ -406,14 +421,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
| 406 | } | 421 | } |
| 407 | 422 | ||
| 408 | init_waitqueue_head(&vif->wq); | 423 | init_waitqueue_head(&vif->wq); |
| 409 | vif->task = kthread_create(xenvif_kthread, | 424 | task = kthread_create(xenvif_kthread, |
| 410 | (void *)vif, "%s", vif->dev->name); | 425 | (void *)vif, "%s", vif->dev->name); |
| 411 | if (IS_ERR(vif->task)) { | 426 | if (IS_ERR(task)) { |
| 412 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); | 427 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); |
| 413 | err = PTR_ERR(vif->task); | 428 | err = PTR_ERR(task); |
| 414 | goto err_rx_unbind; | 429 | goto err_rx_unbind; |
| 415 | } | 430 | } |
| 416 | 431 | ||
| 432 | vif->task = task; | ||
| 433 | |||
| 417 | rtnl_lock(); | 434 | rtnl_lock(); |
| 418 | if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) | 435 | if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) |
| 419 | dev_set_mtu(vif->dev, ETH_DATA_LEN); | 436 | dev_set_mtu(vif->dev, ETH_DATA_LEN); |
| @@ -456,6 +473,11 @@ void xenvif_disconnect(struct xenvif *vif) | |||
| 456 | if (netif_carrier_ok(vif->dev)) | 473 | if (netif_carrier_ok(vif->dev)) |
| 457 | xenvif_carrier_off(vif); | 474 | xenvif_carrier_off(vif); |
| 458 | 475 | ||
| 476 | if (vif->task) { | ||
| 477 | kthread_stop(vif->task); | ||
| 478 | vif->task = NULL; | ||
| 479 | } | ||
| 480 | |||
| 459 | if (vif->tx_irq) { | 481 | if (vif->tx_irq) { |
| 460 | if (vif->tx_irq == vif->rx_irq) | 482 | if (vif->tx_irq == vif->rx_irq) |
| 461 | unbind_from_irqhandler(vif->tx_irq, vif); | 483 | unbind_from_irqhandler(vif->tx_irq, vif); |
| @@ -466,9 +488,6 @@ void xenvif_disconnect(struct xenvif *vif) | |||
| 466 | vif->tx_irq = 0; | 488 | vif->tx_irq = 0; |
| 467 | } | 489 | } |
| 468 | 490 | ||
| 469 | if (vif->task) | ||
| 470 | kthread_stop(vif->task); | ||
| 471 | |||
| 472 | xenvif_unmap_frontend_rings(vif); | 491 | xenvif_unmap_frontend_rings(vif); |
| 473 | } | 492 | } |
| 474 | 493 | ||
| @@ -478,6 +497,7 @@ void xenvif_free(struct xenvif *vif) | |||
| 478 | 497 | ||
| 479 | unregister_netdev(vif->dev); | 498 | unregister_netdev(vif->dev); |
| 480 | 499 | ||
| 500 | vfree(vif->grant_copy_op); | ||
| 481 | free_netdev(vif->dev); | 501 | free_netdev(vif->dev); |
| 482 | 502 | ||
| 483 | module_put(THIS_MODULE); | 503 | module_put(THIS_MODULE); |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index f3e591c611de..78425554a537 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/udp.h> | 39 | #include <linux/udp.h> |
| 40 | 40 | ||
| 41 | #include <net/tcp.h> | 41 | #include <net/tcp.h> |
| 42 | #include <net/ip6_checksum.h> | ||
| 42 | 43 | ||
| 43 | #include <xen/xen.h> | 44 | #include <xen/xen.h> |
| 44 | #include <xen/events.h> | 45 | #include <xen/events.h> |
| @@ -109,15 +110,12 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif, | |||
| 109 | return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx)); | 110 | return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx)); |
| 110 | } | 111 | } |
| 111 | 112 | ||
| 112 | /* | 113 | /* This is a miniumum size for the linear area to avoid lots of |
| 113 | * This is the amount of packet we copy rather than map, so that the | 114 | * calls to __pskb_pull_tail() as we set up checksum offsets. The |
| 114 | * guest can't fiddle with the contents of the headers while we do | 115 | * value 128 was chosen as it covers all IPv4 and most likely |
| 115 | * packet processing on them (netfilter, routing, etc). | 116 | * IPv6 headers. |
| 116 | */ | 117 | */ |
| 117 | #define PKT_PROT_LEN (ETH_HLEN + \ | 118 | #define PKT_PROT_LEN 128 |
| 118 | VLAN_HLEN + \ | ||
| 119 | sizeof(struct iphdr) + MAX_IPOPTLEN + \ | ||
| 120 | sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE) | ||
| 121 | 119 | ||
| 122 | static u16 frag_get_pending_idx(skb_frag_t *frag) | 120 | static u16 frag_get_pending_idx(skb_frag_t *frag) |
| 123 | { | 121 | { |
| @@ -145,7 +143,7 @@ static int max_required_rx_slots(struct xenvif *vif) | |||
| 145 | int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); | 143 | int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); |
| 146 | 144 | ||
| 147 | /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */ | 145 | /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */ |
| 148 | if (vif->can_sg || vif->gso || vif->gso_prefix) | 146 | if (vif->can_sg || vif->gso_mask || vif->gso_prefix_mask) |
| 149 | max += MAX_SKB_FRAGS + 1; /* extra_info + frags */ | 147 | max += MAX_SKB_FRAGS + 1; /* extra_info + frags */ |
| 150 | 148 | ||
| 151 | return max; | 149 | return max; |
| @@ -317,6 +315,7 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif, | |||
| 317 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); | 315 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); |
| 318 | 316 | ||
| 319 | meta = npo->meta + npo->meta_prod++; | 317 | meta = npo->meta + npo->meta_prod++; |
| 318 | meta->gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
| 320 | meta->gso_size = 0; | 319 | meta->gso_size = 0; |
| 321 | meta->size = 0; | 320 | meta->size = 0; |
| 322 | meta->id = req->id; | 321 | meta->id = req->id; |
| @@ -339,6 +338,7 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, | |||
| 339 | struct gnttab_copy *copy_gop; | 338 | struct gnttab_copy *copy_gop; |
| 340 | struct xenvif_rx_meta *meta; | 339 | struct xenvif_rx_meta *meta; |
| 341 | unsigned long bytes; | 340 | unsigned long bytes; |
| 341 | int gso_type; | ||
| 342 | 342 | ||
| 343 | /* Data must not cross a page boundary. */ | 343 | /* Data must not cross a page boundary. */ |
| 344 | BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); | 344 | BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); |
| @@ -397,7 +397,14 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, | |||
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | /* Leave a gap for the GSO descriptor. */ | 399 | /* Leave a gap for the GSO descriptor. */ |
| 400 | if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix) | 400 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) |
| 401 | gso_type = XEN_NETIF_GSO_TYPE_TCPV4; | ||
| 402 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | ||
| 403 | gso_type = XEN_NETIF_GSO_TYPE_TCPV6; | ||
| 404 | else | ||
| 405 | gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
| 406 | |||
| 407 | if (*head && ((1 << gso_type) & vif->gso_mask)) | ||
| 401 | vif->rx.req_cons++; | 408 | vif->rx.req_cons++; |
| 402 | 409 | ||
| 403 | *head = 0; /* There must be something in this buffer now. */ | 410 | *head = 0; /* There must be something in this buffer now. */ |
| @@ -428,14 +435,28 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
| 428 | unsigned char *data; | 435 | unsigned char *data; |
| 429 | int head = 1; | 436 | int head = 1; |
| 430 | int old_meta_prod; | 437 | int old_meta_prod; |
| 438 | int gso_type; | ||
| 439 | int gso_size; | ||
| 431 | 440 | ||
| 432 | old_meta_prod = npo->meta_prod; | 441 | old_meta_prod = npo->meta_prod; |
| 433 | 442 | ||
| 443 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { | ||
| 444 | gso_type = XEN_NETIF_GSO_TYPE_TCPV4; | ||
| 445 | gso_size = skb_shinfo(skb)->gso_size; | ||
| 446 | } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { | ||
| 447 | gso_type = XEN_NETIF_GSO_TYPE_TCPV6; | ||
| 448 | gso_size = skb_shinfo(skb)->gso_size; | ||
| 449 | } else { | ||
| 450 | gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
| 451 | gso_size = 0; | ||
| 452 | } | ||
| 453 | |||
| 434 | /* Set up a GSO prefix descriptor, if necessary */ | 454 | /* Set up a GSO prefix descriptor, if necessary */ |
| 435 | if (skb_shinfo(skb)->gso_size && vif->gso_prefix) { | 455 | if ((1 << gso_type) & vif->gso_prefix_mask) { |
| 436 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); | 456 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); |
| 437 | meta = npo->meta + npo->meta_prod++; | 457 | meta = npo->meta + npo->meta_prod++; |
| 438 | meta->gso_size = skb_shinfo(skb)->gso_size; | 458 | meta->gso_type = gso_type; |
| 459 | meta->gso_size = gso_size; | ||
| 439 | meta->size = 0; | 460 | meta->size = 0; |
| 440 | meta->id = req->id; | 461 | meta->id = req->id; |
| 441 | } | 462 | } |
| @@ -443,10 +464,13 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
| 443 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); | 464 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); |
| 444 | meta = npo->meta + npo->meta_prod++; | 465 | meta = npo->meta + npo->meta_prod++; |
| 445 | 466 | ||
| 446 | if (!vif->gso_prefix) | 467 | if ((1 << gso_type) & vif->gso_mask) { |
| 447 | meta->gso_size = skb_shinfo(skb)->gso_size; | 468 | meta->gso_type = gso_type; |
| 448 | else | 469 | meta->gso_size = gso_size; |
| 470 | } else { | ||
| 471 | meta->gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
| 449 | meta->gso_size = 0; | 472 | meta->gso_size = 0; |
| 473 | } | ||
| 450 | 474 | ||
| 451 | meta->size = 0; | 475 | meta->size = 0; |
| 452 | meta->id = req->id; | 476 | meta->id = req->id; |
| @@ -584,7 +608,7 @@ void xenvif_rx_action(struct xenvif *vif) | |||
| 584 | if (!npo.copy_prod) | 608 | if (!npo.copy_prod) |
| 585 | return; | 609 | return; |
| 586 | 610 | ||
| 587 | BUG_ON(npo.copy_prod > ARRAY_SIZE(vif->grant_copy_op)); | 611 | BUG_ON(npo.copy_prod > MAX_GRANT_COPY_OPS); |
| 588 | gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); | 612 | gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); |
| 589 | 613 | ||
| 590 | while ((skb = __skb_dequeue(&rxq)) != NULL) { | 614 | while ((skb = __skb_dequeue(&rxq)) != NULL) { |
| @@ -592,7 +616,8 @@ void xenvif_rx_action(struct xenvif *vif) | |||
| 592 | 616 | ||
| 593 | vif = netdev_priv(skb->dev); | 617 | vif = netdev_priv(skb->dev); |
| 594 | 618 | ||
| 595 | if (vif->meta[npo.meta_cons].gso_size && vif->gso_prefix) { | 619 | if ((1 << vif->meta[npo.meta_cons].gso_type) & |
| 620 | vif->gso_prefix_mask) { | ||
| 596 | resp = RING_GET_RESPONSE(&vif->rx, | 621 | resp = RING_GET_RESPONSE(&vif->rx, |
| 597 | vif->rx.rsp_prod_pvt++); | 622 | vif->rx.rsp_prod_pvt++); |
| 598 | 623 | ||
| @@ -629,7 +654,8 @@ void xenvif_rx_action(struct xenvif *vif) | |||
| 629 | vif->meta[npo.meta_cons].size, | 654 | vif->meta[npo.meta_cons].size, |
| 630 | flags); | 655 | flags); |
| 631 | 656 | ||
| 632 | if (vif->meta[npo.meta_cons].gso_size && !vif->gso_prefix) { | 657 | if ((1 << vif->meta[npo.meta_cons].gso_type) & |
| 658 | vif->gso_mask) { | ||
| 633 | struct xen_netif_extra_info *gso = | 659 | struct xen_netif_extra_info *gso = |
| 634 | (struct xen_netif_extra_info *) | 660 | (struct xen_netif_extra_info *) |
| 635 | RING_GET_RESPONSE(&vif->rx, | 661 | RING_GET_RESPONSE(&vif->rx, |
| @@ -637,8 +663,8 @@ void xenvif_rx_action(struct xenvif *vif) | |||
| 637 | 663 | ||
| 638 | resp->flags |= XEN_NETRXF_extra_info; | 664 | resp->flags |= XEN_NETRXF_extra_info; |
| 639 | 665 | ||
| 666 | gso->u.gso.type = vif->meta[npo.meta_cons].gso_type; | ||
| 640 | gso->u.gso.size = vif->meta[npo.meta_cons].gso_size; | 667 | gso->u.gso.size = vif->meta[npo.meta_cons].gso_size; |
| 641 | gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; | ||
| 642 | gso->u.gso.pad = 0; | 668 | gso->u.gso.pad = 0; |
| 643 | gso->u.gso.features = 0; | 669 | gso->u.gso.features = 0; |
| 644 | 670 | ||
| @@ -1101,15 +1127,20 @@ static int xenvif_set_skb_gso(struct xenvif *vif, | |||
| 1101 | return -EINVAL; | 1127 | return -EINVAL; |
| 1102 | } | 1128 | } |
| 1103 | 1129 | ||
| 1104 | /* Currently only TCPv4 S.O. is supported. */ | 1130 | switch (gso->u.gso.type) { |
| 1105 | if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { | 1131 | case XEN_NETIF_GSO_TYPE_TCPV4: |
| 1132 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | ||
| 1133 | break; | ||
| 1134 | case XEN_NETIF_GSO_TYPE_TCPV6: | ||
| 1135 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | ||
| 1136 | break; | ||
| 1137 | default: | ||
| 1106 | netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); | 1138 | netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); |
| 1107 | xenvif_fatal_tx_err(vif); | 1139 | xenvif_fatal_tx_err(vif); |
| 1108 | return -EINVAL; | 1140 | return -EINVAL; |
| 1109 | } | 1141 | } |
| 1110 | 1142 | ||
| 1111 | skb_shinfo(skb)->gso_size = gso->u.gso.size; | 1143 | skb_shinfo(skb)->gso_size = gso->u.gso.size; |
| 1112 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | ||
| 1113 | 1144 | ||
| 1114 | /* Header must be checked, and gso_segs computed. */ | 1145 | /* Header must be checked, and gso_segs computed. */ |
| 1115 | skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; | 1146 | skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; |
| @@ -1118,62 +1149,244 @@ static int xenvif_set_skb_gso(struct xenvif *vif, | |||
| 1118 | return 0; | 1149 | return 0; |
| 1119 | } | 1150 | } |
| 1120 | 1151 | ||
| 1121 | static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) | 1152 | static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len, |
| 1153 | unsigned int max) | ||
| 1122 | { | 1154 | { |
| 1123 | struct iphdr *iph; | 1155 | if (skb_headlen(skb) >= len) |
| 1124 | int err = -EPROTO; | 1156 | return 0; |
| 1125 | int recalculate_partial_csum = 0; | ||
| 1126 | 1157 | ||
| 1127 | /* | 1158 | /* If we need to pullup then pullup to the max, so we |
| 1128 | * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy | 1159 | * won't need to do it again. |
| 1129 | * peers can fail to set NETRXF_csum_blank when sending a GSO | ||
| 1130 | * frame. In this case force the SKB to CHECKSUM_PARTIAL and | ||
| 1131 | * recalculate the partial checksum. | ||
| 1132 | */ | 1160 | */ |
| 1133 | if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { | 1161 | if (max > skb->len) |
| 1134 | vif->rx_gso_checksum_fixup++; | 1162 | max = skb->len; |
| 1135 | skb->ip_summed = CHECKSUM_PARTIAL; | 1163 | |
| 1136 | recalculate_partial_csum = 1; | 1164 | if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) |
| 1165 | return -ENOMEM; | ||
| 1166 | |||
| 1167 | if (skb_headlen(skb) < len) | ||
| 1168 | return -EPROTO; | ||
| 1169 | |||
| 1170 | return 0; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | /* This value should be large enough to cover a tagged ethernet header plus | ||
| 1174 | * maximally sized IP and TCP or UDP headers. | ||
| 1175 | */ | ||
| 1176 | #define MAX_IP_HDR_LEN 128 | ||
| 1177 | |||
| 1178 | static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, | ||
| 1179 | int recalculate_partial_csum) | ||
| 1180 | { | ||
| 1181 | unsigned int off; | ||
| 1182 | bool fragment; | ||
| 1183 | int err; | ||
| 1184 | |||
| 1185 | fragment = false; | ||
| 1186 | |||
| 1187 | err = maybe_pull_tail(skb, | ||
| 1188 | sizeof(struct iphdr), | ||
| 1189 | MAX_IP_HDR_LEN); | ||
| 1190 | if (err < 0) | ||
| 1191 | goto out; | ||
| 1192 | |||
| 1193 | if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) | ||
| 1194 | fragment = true; | ||
| 1195 | |||
| 1196 | off = ip_hdrlen(skb); | ||
| 1197 | |||
| 1198 | err = -EPROTO; | ||
| 1199 | |||
| 1200 | if (fragment) | ||
| 1201 | goto out; | ||
| 1202 | |||
| 1203 | switch (ip_hdr(skb)->protocol) { | ||
| 1204 | case IPPROTO_TCP: | ||
| 1205 | err = maybe_pull_tail(skb, | ||
| 1206 | off + sizeof(struct tcphdr), | ||
| 1207 | MAX_IP_HDR_LEN); | ||
| 1208 | if (err < 0) | ||
| 1209 | goto out; | ||
| 1210 | |||
| 1211 | if (!skb_partial_csum_set(skb, off, | ||
| 1212 | offsetof(struct tcphdr, check))) { | ||
| 1213 | err = -EPROTO; | ||
| 1214 | goto out; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | if (recalculate_partial_csum) | ||
| 1218 | tcp_hdr(skb)->check = | ||
| 1219 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
| 1220 | ip_hdr(skb)->daddr, | ||
| 1221 | skb->len - off, | ||
| 1222 | IPPROTO_TCP, 0); | ||
| 1223 | break; | ||
| 1224 | case IPPROTO_UDP: | ||
| 1225 | err = maybe_pull_tail(skb, | ||
| 1226 | off + sizeof(struct udphdr), | ||
| 1227 | MAX_IP_HDR_LEN); | ||
| 1228 | if (err < 0) | ||
| 1229 | goto out; | ||
| 1230 | |||
| 1231 | if (!skb_partial_csum_set(skb, off, | ||
| 1232 | offsetof(struct udphdr, check))) { | ||
| 1233 | err = -EPROTO; | ||
| 1234 | goto out; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | if (recalculate_partial_csum) | ||
| 1238 | udp_hdr(skb)->check = | ||
| 1239 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
| 1240 | ip_hdr(skb)->daddr, | ||
| 1241 | skb->len - off, | ||
| 1242 | IPPROTO_UDP, 0); | ||
| 1243 | break; | ||
| 1244 | default: | ||
| 1245 | goto out; | ||
| 1137 | } | 1246 | } |
| 1138 | 1247 | ||
| 1139 | /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ | 1248 | err = 0; |
| 1140 | if (skb->ip_summed != CHECKSUM_PARTIAL) | 1249 | |
| 1141 | return 0; | 1250 | out: |
| 1251 | return err; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | /* This value should be large enough to cover a tagged ethernet header plus | ||
| 1255 | * an IPv6 header, all options, and a maximal TCP or UDP header. | ||
| 1256 | */ | ||
| 1257 | #define MAX_IPV6_HDR_LEN 256 | ||
| 1258 | |||
| 1259 | #define OPT_HDR(type, skb, off) \ | ||
| 1260 | (type *)(skb_network_header(skb) + (off)) | ||
| 1261 | |||
| 1262 | static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, | ||
| 1263 | int recalculate_partial_csum) | ||
| 1264 | { | ||
| 1265 | int err; | ||
| 1266 | u8 nexthdr; | ||
| 1267 | unsigned int off; | ||
| 1268 | unsigned int len; | ||
| 1269 | bool fragment; | ||
| 1270 | bool done; | ||
| 1271 | |||
| 1272 | fragment = false; | ||
| 1273 | done = false; | ||
| 1274 | |||
| 1275 | off = sizeof(struct ipv6hdr); | ||
| 1276 | |||
| 1277 | err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); | ||
| 1278 | if (err < 0) | ||
| 1279 | goto out; | ||
| 1280 | |||
| 1281 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 1282 | |||
| 1283 | len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); | ||
| 1284 | while (off <= len && !done) { | ||
| 1285 | switch (nexthdr) { | ||
| 1286 | case IPPROTO_DSTOPTS: | ||
| 1287 | case IPPROTO_HOPOPTS: | ||
| 1288 | case IPPROTO_ROUTING: { | ||
| 1289 | struct ipv6_opt_hdr *hp; | ||
| 1290 | |||
| 1291 | err = maybe_pull_tail(skb, | ||
| 1292 | off + | ||
| 1293 | sizeof(struct ipv6_opt_hdr), | ||
| 1294 | MAX_IPV6_HDR_LEN); | ||
| 1295 | if (err < 0) | ||
| 1296 | goto out; | ||
| 1297 | |||
| 1298 | hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); | ||
| 1299 | nexthdr = hp->nexthdr; | ||
| 1300 | off += ipv6_optlen(hp); | ||
| 1301 | break; | ||
| 1302 | } | ||
| 1303 | case IPPROTO_AH: { | ||
| 1304 | struct ip_auth_hdr *hp; | ||
| 1305 | |||
| 1306 | err = maybe_pull_tail(skb, | ||
| 1307 | off + | ||
| 1308 | sizeof(struct ip_auth_hdr), | ||
| 1309 | MAX_IPV6_HDR_LEN); | ||
| 1310 | if (err < 0) | ||
| 1311 | goto out; | ||
| 1312 | |||
| 1313 | hp = OPT_HDR(struct ip_auth_hdr, skb, off); | ||
| 1314 | nexthdr = hp->nexthdr; | ||
| 1315 | off += ipv6_authlen(hp); | ||
| 1316 | break; | ||
| 1317 | } | ||
| 1318 | case IPPROTO_FRAGMENT: { | ||
| 1319 | struct frag_hdr *hp; | ||
| 1320 | |||
| 1321 | err = maybe_pull_tail(skb, | ||
| 1322 | off + | ||
| 1323 | sizeof(struct frag_hdr), | ||
| 1324 | MAX_IPV6_HDR_LEN); | ||
| 1325 | if (err < 0) | ||
| 1326 | goto out; | ||
| 1327 | |||
| 1328 | hp = OPT_HDR(struct frag_hdr, skb, off); | ||
| 1329 | |||
| 1330 | if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) | ||
| 1331 | fragment = true; | ||
| 1332 | |||
| 1333 | nexthdr = hp->nexthdr; | ||
| 1334 | off += sizeof(struct frag_hdr); | ||
| 1335 | break; | ||
| 1336 | } | ||
| 1337 | default: | ||
| 1338 | done = true; | ||
| 1339 | break; | ||
| 1340 | } | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | err = -EPROTO; | ||
| 1142 | 1344 | ||
| 1143 | if (skb->protocol != htons(ETH_P_IP)) | 1345 | if (!done || fragment) |
| 1144 | goto out; | 1346 | goto out; |
| 1145 | 1347 | ||
| 1146 | iph = (void *)skb->data; | 1348 | switch (nexthdr) { |
| 1147 | switch (iph->protocol) { | ||
| 1148 | case IPPROTO_TCP: | 1349 | case IPPROTO_TCP: |
| 1149 | if (!skb_partial_csum_set(skb, 4 * iph->ihl, | 1350 | err = maybe_pull_tail(skb, |
| 1150 | offsetof(struct tcphdr, check))) | 1351 | off + sizeof(struct tcphdr), |
| 1352 | MAX_IPV6_HDR_LEN); | ||
| 1353 | if (err < 0) | ||
| 1151 | goto out; | 1354 | goto out; |
| 1152 | 1355 | ||
| 1153 | if (recalculate_partial_csum) { | 1356 | if (!skb_partial_csum_set(skb, off, |
| 1154 | struct tcphdr *tcph = tcp_hdr(skb); | 1357 | offsetof(struct tcphdr, check))) { |
| 1155 | tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | 1358 | err = -EPROTO; |
| 1156 | skb->len - iph->ihl*4, | 1359 | goto out; |
| 1157 | IPPROTO_TCP, 0); | ||
| 1158 | } | 1360 | } |
| 1361 | |||
| 1362 | if (recalculate_partial_csum) | ||
| 1363 | tcp_hdr(skb)->check = | ||
| 1364 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
| 1365 | &ipv6_hdr(skb)->daddr, | ||
| 1366 | skb->len - off, | ||
| 1367 | IPPROTO_TCP, 0); | ||
| 1159 | break; | 1368 | break; |
| 1160 | case IPPROTO_UDP: | 1369 | case IPPROTO_UDP: |
| 1161 | if (!skb_partial_csum_set(skb, 4 * iph->ihl, | 1370 | err = maybe_pull_tail(skb, |
| 1162 | offsetof(struct udphdr, check))) | 1371 | off + sizeof(struct udphdr), |
| 1372 | MAX_IPV6_HDR_LEN); | ||
| 1373 | if (err < 0) | ||
| 1163 | goto out; | 1374 | goto out; |
| 1164 | 1375 | ||
| 1165 | if (recalculate_partial_csum) { | 1376 | if (!skb_partial_csum_set(skb, off, |
| 1166 | struct udphdr *udph = udp_hdr(skb); | 1377 | offsetof(struct udphdr, check))) { |
| 1167 | udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | 1378 | err = -EPROTO; |
| 1168 | skb->len - iph->ihl*4, | 1379 | goto out; |
| 1169 | IPPROTO_UDP, 0); | ||
| 1170 | } | 1380 | } |
| 1381 | |||
| 1382 | if (recalculate_partial_csum) | ||
| 1383 | udp_hdr(skb)->check = | ||
| 1384 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
| 1385 | &ipv6_hdr(skb)->daddr, | ||
| 1386 | skb->len - off, | ||
| 1387 | IPPROTO_UDP, 0); | ||
| 1171 | break; | 1388 | break; |
| 1172 | default: | 1389 | default: |
| 1173 | if (net_ratelimit()) | ||
| 1174 | netdev_err(vif->dev, | ||
| 1175 | "Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n", | ||
| 1176 | iph->protocol); | ||
| 1177 | goto out; | 1390 | goto out; |
| 1178 | } | 1391 | } |
| 1179 | 1392 | ||
| @@ -1183,11 +1396,38 @@ out: | |||
| 1183 | return err; | 1396 | return err; |
| 1184 | } | 1397 | } |
| 1185 | 1398 | ||
| 1399 | static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) | ||
| 1400 | { | ||
| 1401 | int err = -EPROTO; | ||
| 1402 | int recalculate_partial_csum = 0; | ||
| 1403 | |||
| 1404 | /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy | ||
| 1405 | * peers can fail to set NETRXF_csum_blank when sending a GSO | ||
| 1406 | * frame. In this case force the SKB to CHECKSUM_PARTIAL and | ||
| 1407 | * recalculate the partial checksum. | ||
| 1408 | */ | ||
| 1409 | if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { | ||
| 1410 | vif->rx_gso_checksum_fixup++; | ||
| 1411 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 1412 | recalculate_partial_csum = 1; | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ | ||
| 1416 | if (skb->ip_summed != CHECKSUM_PARTIAL) | ||
| 1417 | return 0; | ||
| 1418 | |||
| 1419 | if (skb->protocol == htons(ETH_P_IP)) | ||
| 1420 | err = checksum_setup_ip(vif, skb, recalculate_partial_csum); | ||
| 1421 | else if (skb->protocol == htons(ETH_P_IPV6)) | ||
| 1422 | err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum); | ||
| 1423 | |||
| 1424 | return err; | ||
| 1425 | } | ||
| 1426 | |||
| 1186 | static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | 1427 | static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) |
| 1187 | { | 1428 | { |
| 1188 | unsigned long now = jiffies; | 1429 | u64 now = get_jiffies_64(); |
| 1189 | unsigned long next_credit = | 1430 | u64 next_credit = vif->credit_window_start + |
| 1190 | vif->credit_timeout.expires + | ||
| 1191 | msecs_to_jiffies(vif->credit_usec / 1000); | 1431 | msecs_to_jiffies(vif->credit_usec / 1000); |
| 1192 | 1432 | ||
| 1193 | /* Timer could already be pending in rare cases. */ | 1433 | /* Timer could already be pending in rare cases. */ |
| @@ -1195,8 +1435,8 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | |||
| 1195 | return true; | 1435 | return true; |
| 1196 | 1436 | ||
| 1197 | /* Passed the point where we can replenish credit? */ | 1437 | /* Passed the point where we can replenish credit? */ |
| 1198 | if (time_after_eq(now, next_credit)) { | 1438 | if (time_after_eq64(now, next_credit)) { |
| 1199 | vif->credit_timeout.expires = now; | 1439 | vif->credit_window_start = now; |
| 1200 | tx_add_credit(vif); | 1440 | tx_add_credit(vif); |
| 1201 | } | 1441 | } |
| 1202 | 1442 | ||
| @@ -1208,6 +1448,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | |||
| 1208 | tx_credit_callback; | 1448 | tx_credit_callback; |
| 1209 | mod_timer(&vif->credit_timeout, | 1449 | mod_timer(&vif->credit_timeout, |
| 1210 | next_credit); | 1450 | next_credit); |
| 1451 | vif->credit_window_start = next_credit; | ||
| 1211 | 1452 | ||
| 1212 | return true; | 1453 | return true; |
| 1213 | } | 1454 | } |
| @@ -1215,14 +1456,15 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | |||
| 1215 | return false; | 1456 | return false; |
| 1216 | } | 1457 | } |
| 1217 | 1458 | ||
| 1218 | static unsigned xenvif_tx_build_gops(struct xenvif *vif) | 1459 | static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) |
| 1219 | { | 1460 | { |
| 1220 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; | 1461 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; |
| 1221 | struct sk_buff *skb; | 1462 | struct sk_buff *skb; |
| 1222 | int ret; | 1463 | int ret; |
| 1223 | 1464 | ||
| 1224 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX | 1465 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX |
| 1225 | < MAX_PENDING_REQS)) { | 1466 | < MAX_PENDING_REQS) && |
| 1467 | (skb_queue_len(&vif->tx_queue) < budget)) { | ||
| 1226 | struct xen_netif_tx_request txreq; | 1468 | struct xen_netif_tx_request txreq; |
| 1227 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; | 1469 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; |
| 1228 | struct page *page; | 1470 | struct page *page; |
| @@ -1244,7 +1486,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
| 1244 | continue; | 1486 | continue; |
| 1245 | } | 1487 | } |
| 1246 | 1488 | ||
| 1247 | RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do); | 1489 | work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); |
| 1248 | if (!work_to_do) | 1490 | if (!work_to_do) |
| 1249 | break; | 1491 | break; |
| 1250 | 1492 | ||
| @@ -1384,14 +1626,13 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
| 1384 | } | 1626 | } |
| 1385 | 1627 | ||
| 1386 | 1628 | ||
| 1387 | static int xenvif_tx_submit(struct xenvif *vif, int budget) | 1629 | static int xenvif_tx_submit(struct xenvif *vif) |
| 1388 | { | 1630 | { |
| 1389 | struct gnttab_copy *gop = vif->tx_copy_ops; | 1631 | struct gnttab_copy *gop = vif->tx_copy_ops; |
| 1390 | struct sk_buff *skb; | 1632 | struct sk_buff *skb; |
| 1391 | int work_done = 0; | 1633 | int work_done = 0; |
| 1392 | 1634 | ||
| 1393 | while (work_done < budget && | 1635 | while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) { |
| 1394 | (skb = __skb_dequeue(&vif->tx_queue)) != NULL) { | ||
| 1395 | struct xen_netif_tx_request *txp; | 1636 | struct xen_netif_tx_request *txp; |
| 1396 | u16 pending_idx; | 1637 | u16 pending_idx; |
| 1397 | unsigned data_len; | 1638 | unsigned data_len; |
| @@ -1428,12 +1669,7 @@ static int xenvif_tx_submit(struct xenvif *vif, int budget) | |||
| 1428 | 1669 | ||
| 1429 | xenvif_fill_frags(vif, skb); | 1670 | xenvif_fill_frags(vif, skb); |
| 1430 | 1671 | ||
| 1431 | /* | 1672 | if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) { |
| 1432 | * If the initial fragment was < PKT_PROT_LEN then | ||
| 1433 | * pull through some bytes from the other fragments to | ||
| 1434 | * increase the linear region to PKT_PROT_LEN bytes. | ||
| 1435 | */ | ||
| 1436 | if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) { | ||
| 1437 | int target = min_t(int, skb->len, PKT_PROT_LEN); | 1673 | int target = min_t(int, skb->len, PKT_PROT_LEN); |
| 1438 | __pskb_pull_tail(skb, target - skb_headlen(skb)); | 1674 | __pskb_pull_tail(skb, target - skb_headlen(skb)); |
| 1439 | } | 1675 | } |
| @@ -1471,14 +1707,14 @@ int xenvif_tx_action(struct xenvif *vif, int budget) | |||
| 1471 | if (unlikely(!tx_work_todo(vif))) | 1707 | if (unlikely(!tx_work_todo(vif))) |
| 1472 | return 0; | 1708 | return 0; |
| 1473 | 1709 | ||
| 1474 | nr_gops = xenvif_tx_build_gops(vif); | 1710 | nr_gops = xenvif_tx_build_gops(vif, budget); |
| 1475 | 1711 | ||
| 1476 | if (nr_gops == 0) | 1712 | if (nr_gops == 0) |
| 1477 | return 0; | 1713 | return 0; |
| 1478 | 1714 | ||
| 1479 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); | 1715 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); |
| 1480 | 1716 | ||
| 1481 | work_done = xenvif_tx_submit(vif, nr_gops); | 1717 | work_done = xenvif_tx_submit(vif); |
| 1482 | 1718 | ||
| 1483 | return work_done; | 1719 | return work_done; |
| 1484 | } | 1720 | } |
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 1b08d8798372..f0358992b04f 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c | |||
| @@ -105,6 +105,22 @@ static int netback_probe(struct xenbus_device *dev, | |||
| 105 | goto abort_transaction; | 105 | goto abort_transaction; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv6", | ||
| 109 | "%d", sg); | ||
| 110 | if (err) { | ||
| 111 | message = "writing feature-gso-tcpv6"; | ||
| 112 | goto abort_transaction; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* We support partial checksum setup for IPv6 packets */ | ||
| 116 | err = xenbus_printf(xbt, dev->nodename, | ||
| 117 | "feature-ipv6-csum-offload", | ||
| 118 | "%d", 1); | ||
| 119 | if (err) { | ||
| 120 | message = "writing feature-ipv6-csum-offload"; | ||
| 121 | goto abort_transaction; | ||
| 122 | } | ||
| 123 | |||
| 108 | /* We support rx-copy path. */ | 124 | /* We support rx-copy path. */ |
| 109 | err = xenbus_printf(xbt, dev->nodename, | 125 | err = xenbus_printf(xbt, dev->nodename, |
| 110 | "feature-rx-copy", "%d", 1); | 126 | "feature-rx-copy", "%d", 1); |
| @@ -561,20 +577,50 @@ static int connect_rings(struct backend_info *be) | |||
| 561 | val = 0; | 577 | val = 0; |
| 562 | vif->can_sg = !!val; | 578 | vif->can_sg = !!val; |
| 563 | 579 | ||
| 580 | vif->gso_mask = 0; | ||
| 581 | vif->gso_prefix_mask = 0; | ||
| 582 | |||
| 564 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", | 583 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", |
| 565 | "%d", &val) < 0) | 584 | "%d", &val) < 0) |
| 566 | val = 0; | 585 | val = 0; |
| 567 | vif->gso = !!val; | 586 | if (val) |
| 587 | vif->gso_mask |= GSO_BIT(TCPV4); | ||
| 568 | 588 | ||
| 569 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix", | 589 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix", |
| 570 | "%d", &val) < 0) | 590 | "%d", &val) < 0) |
| 571 | val = 0; | 591 | val = 0; |
| 572 | vif->gso_prefix = !!val; | 592 | if (val) |
| 593 | vif->gso_prefix_mask |= GSO_BIT(TCPV4); | ||
| 594 | |||
| 595 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv6", | ||
| 596 | "%d", &val) < 0) | ||
| 597 | val = 0; | ||
| 598 | if (val) | ||
| 599 | vif->gso_mask |= GSO_BIT(TCPV6); | ||
| 600 | |||
| 601 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv6-prefix", | ||
| 602 | "%d", &val) < 0) | ||
| 603 | val = 0; | ||
| 604 | if (val) | ||
| 605 | vif->gso_prefix_mask |= GSO_BIT(TCPV6); | ||
| 606 | |||
| 607 | if (vif->gso_mask & vif->gso_prefix_mask) { | ||
| 608 | xenbus_dev_fatal(dev, err, | ||
| 609 | "%s: gso and gso prefix flags are not " | ||
| 610 | "mutually exclusive", | ||
| 611 | dev->otherend); | ||
| 612 | return -EOPNOTSUPP; | ||
| 613 | } | ||
| 573 | 614 | ||
| 574 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload", | 615 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload", |
| 575 | "%d", &val) < 0) | 616 | "%d", &val) < 0) |
| 576 | val = 0; | 617 | val = 0; |
| 577 | vif->csum = !val; | 618 | vif->ip_csum = !val; |
| 619 | |||
| 620 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-ipv6-csum-offload", | ||
| 621 | "%d", &val) < 0) | ||
| 622 | val = 0; | ||
| 623 | vif->ipv6_csum = !!val; | ||
| 578 | 624 | ||
| 579 | /* Map the shared frame, irq etc. */ | 625 | /* Map the shared frame, irq etc. */ |
| 580 | err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, | 626 | err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, |
