datapath: Hold rcu_read_lock where we claim to.
[openvswitch] / datapath / vport-gre.c
index a272b8a3fb8a3ba2cdd37063bc0a68dc5c675457..bd6d4a3c283e8d8ac54f8ff3a789c152445f23a0 100644 (file)
@@ -534,6 +534,7 @@ send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
            mutable->port_config.flags & GRE_F_OUT_KEY_ACTION)
                OVS_CB(nskb)->tun_id = flow_key;
 
+       compute_ip_summed(nskb, false);
        vport_receive(vport, nskb);
 
        return true;
@@ -728,11 +729,13 @@ handle_csum_offload(struct sk_buff *skb)
 {
        if (skb->ip_summed == CHECKSUM_PARTIAL)
                return skb_checksum_help(skb);
-       else
+       else {
+               skb->ip_summed = CHECKSUM_NONE;
                return 0;
+       }
 }
 
-/* Called with rcu_read_lock and bottom-halves disabled. */
+/* Called with rcu_read_lock. */
 static void
 gre_err(struct sk_buff *skb, u32 info)
 {
@@ -844,7 +847,7 @@ out:
        skb->protocol = htons(ETH_P_IP);
 }
 
-/* Called with rcu_read_lock and bottom-halves disabled. */
+/* Called with rcu_read_lock. */
 static int
 gre_rcv(struct sk_buff *skb)
 {
@@ -900,6 +903,8 @@ gre_rcv(struct sk_buff *skb)
                OVS_CB(skb)->tun_id = 0;
 
        skb_push(skb, ETH_HLEN);
+       compute_ip_summed(skb, false);
+
        vport_receive(vport, skb);
 
        return 0;
@@ -960,6 +965,10 @@ build_packet(struct vport *vport, const struct mutable_config *mutable,
 
        create_gre_header(skb, mutable);
 
+       /* Allow our local IP stack to fragment the outer packet even if the
+        * DF bit is set as a last resort. */
+       skb->local_df = 1;
+
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags = 0;
 
@@ -1067,15 +1076,10 @@ gre_send(struct vport *vport, struct sk_buff *skb)
        iph.daddr = rt->rt_dst;
        iph.saddr = rt->rt_src;
 
-       /* Allow our local IP stack to fragment the outer packet even if the
-        * DF bit is set as a last resort. */
-       skb->local_df = 1;
-
        nf_reset(skb);
        secpath_reset(skb);
        skb_dst_drop(skb);
        skb_dst_set(skb, &rt->u.dst);
-       skb->ip_summed = CHECKSUM_NONE;
 
        /* If we are doing GSO on a pskb it is better to make sure that the
         * headroom is correct now.  We will only have to copy the portion in
@@ -1083,7 +1087,9 @@ gre_send(struct vport *vport, struct sk_buff *skb)
         * the segments.  This is particularly beneficial on Xen where we get
         * lots of GSO pskbs.  Conversely, we delay copying if it is just to
         * get our own writable clone because GSO may do the copy for us. */
-       max_headroom = LL_RESERVED_SPACE(rt->u.dst.dev) + mutable->tunnel_hlen;
+       max_headroom = LL_RESERVED_SPACE(rt->u.dst.dev) + rt->u.dst.header_len
+                       + mutable->tunnel_hlen;
+
        if (skb_headroom(skb) < max_headroom) {
                skb = check_headroom(skb, max_headroom);
                if (unlikely(IS_ERR(skb))) {
@@ -1092,14 +1098,16 @@ gre_send(struct vport *vport, struct sk_buff *skb)
                }
        }
 
+       forward_ip_summed(skb);
        vswitch_skb_checksum_setup(skb);
+
        skb = handle_gso(skb);
        if (unlikely(IS_ERR(skb))) {
                vport_record_error(vport, VPORT_E_TX_DROPPED);
                goto error;
        }
 
-       /* Process GSO segments.  Try to do any work on the entire packet that
+       /* Process GSO segments.  Try to do any work for the entire packet that
         * doesn't involve actually writing to it before this point. */
        orig_len = 0;
        do {