- skb->csum = ~csum_partial((char *)diff, sizeof(diff),
- ~skb->csum);
- }
- } else {
- /* Add vlan header */
-
- /* Set up checksumming pointers for checksum-deferred packets
- * on Xen. Otherwise, dev_queue_xmit() will try to do this
- * when we send the packet out on the wire, and it will fail at
- * that point because skb_checksum_setup() will not look inside
- * an 802.1Q header. */
- vswitch_skb_checksum_setup(skb);
-
- /* GSO is not implemented for packets with an 802.1Q header, so
- * we have to do segmentation before we add that header.
- *
- * GSO does work with hardware-accelerated VLAN tagging, but we
- * can't use hardware-accelerated VLAN tagging since it
- * requires the device to have a VLAN group configured (with
- * e.g. vconfig(8)) and we don't do that.
- *
- * Having to do this here may be a performance loss, since we
- * can't take advantage of TSO hardware support, although it
- * does not make a measurable network performance difference
- * for 1G Ethernet. Fixing that would require patching the
- * kernel (either to add GSO support to the VLAN protocol or to
- * support hardware-accelerated VLAN tagging without VLAN
- * groups configured). */
- if (skb_is_gso(skb)) {
- struct sk_buff *segs;
-
- segs = skb_gso_segment(skb, 0);
- kfree_skb(skb);
- if (unlikely(IS_ERR(segs)))
- return ERR_CAST(segs);
-
- do {
- struct sk_buff *nskb = segs->next;
- int err;
-
- segs->next = NULL;
-
- /* GSO can change the checksum type so update.*/
- compute_ip_summed(segs, true);
-
- segs = __vlan_put_tag(segs, tci);
- err = -ENOMEM;
- if (segs) {
- struct odp_flow_key segkey = *key;
- err = execute_actions(dp, segs,
- &segkey, a + 1,
- n_actions - 1,
- gfp);
- }
-
- if (unlikely(err)) {
- while ((segs = nskb)) {
- nskb = segs->next;
- segs->next = NULL;
- kfree_skb(segs);
- }
- return ERR_PTR(err);
- }
-
- segs = nskb;
- } while (segs->next);
-
- skb = segs;
- compute_ip_summed(skb, true);
- }