tests: Add bundle action test with buffer realloc.
[cascardo/ovs.git] / datapath / actions.c
index c6b3ca9..20413c9 100644 (file)
@@ -60,7 +60,7 @@ struct deferred_action {
 struct ovs_frag_data {
        unsigned long dst;
        struct vport *vport;
-       struct ovs_skb_cb cb;
+       struct ovs_gso_cb cb;
        __be16 inner_protocol;
        __u16 vlan_tci;
        __be16 vlan_proto;
@@ -68,7 +68,9 @@ struct ovs_frag_data {
        u8 l2_data[MAX_L2_LEN];
 };
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
 static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage);
+#endif
 
 #define DEFERRED_ACTION_FIFO_SIZE 10
 struct action_fifo {
@@ -623,7 +625,7 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key,
        return 0;
 }
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3,9,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
 static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS)
 {
        struct ovs_frag_data *data = get_pcpu_ptr(ovs_frag_data_storage);
@@ -635,7 +637,7 @@ static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS)
        }
 
        __skb_dst_copy(skb, data->dst);
-       *OVS_CB(skb) = data->cb;
+       *OVS_GSO_CB(skb) = data->cb;
        ovs_skb_set_inner_protocol(skb, data->inner_protocol);
        skb->vlan_tci = data->vlan_tci;
        skb->vlan_proto = data->vlan_proto;
@@ -672,7 +674,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb)
        data = get_pcpu_ptr(ovs_frag_data_storage);
        data->dst = (unsigned long) skb_dst(skb);
        data->vport = vport;
-       data->cb = *OVS_CB(skb);
+       data->cb = *OVS_GSO_CB(skb);
        data->inner_protocol = ovs_skb_get_inner_protocol(skb);
        data->vlan_tci = skb->vlan_tci;
        data->vlan_proto = skb->vlan_proto;
@@ -688,7 +690,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
 {
        if (skb_network_offset(skb) > MAX_L2_LEN) {
                OVS_NLERR(1, "L2 header too long to fragment");
-               return;
+               goto err;
        }
 
        if (ethertype == htons(ETH_P_IP)) {
@@ -712,8 +714,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
                struct rt6_info ovs_rt;
 
                if (!v6ops) {
-                       kfree_skb(skb);
-                       return;
+                       goto err;
                }
 
                prepare_frag(vport, skb);
@@ -732,10 +733,14 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
                WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
                          ovs_vport_name(vport), ntohs(ethertype), mru,
                          vport->dev->mtu);
-               kfree_skb(skb);
+               goto err;
        }
+
+       return;
+err:
+       kfree_skb(skb);
 }
-#else /* <= 3.9 */
+#else /* < 3.10 */
 static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
                         __be16 ethertype)
 {
@@ -982,7 +987,7 @@ static int execute_masked_set_action(struct sk_buff *skb,
        case OVS_KEY_ATTR_CT_STATE:
        case OVS_KEY_ATTR_CT_ZONE:
        case OVS_KEY_ATTR_CT_MARK:
-       case OVS_KEY_ATTR_CT_LABEL:
+       case OVS_KEY_ATTR_CT_LABELS:
                err = -EINVAL;
                break;
        }
@@ -1113,12 +1118,18 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                        break;
 
                case OVS_ACTION_ATTR_CT:
+                       if (!is_flow_key_valid(key)) {
+                               err = ovs_flow_key_update(skb, key);
+                               if (err)
+                                       return err;
+                       }
+
                        err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key,
                                             nla_data(a));
 
                        /* Hide stolen IP fragments from user space. */
-                       if (err == -EINPROGRESS)
-                               return 0;
+                       if (err)
+                               return err == -EINPROGRESS ? 0 : err;
                        break;
                }