datapath: Move is_frag out of struct ovs_skb_cb.
[sliver-openvswitch.git] / datapath / datapath.c
index a34049f..5996d6e 100644 (file)
@@ -8,6 +8,8 @@
 
 /* Functions for managing the dp interface/device. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -27,7 +29,6 @@
 #include <linux/udp.h>
 #include <linux/version.h>
 #include <linux/ethtool.h>
-#include <linux/random.h>
 #include <linux/wait.h>
 #include <asm/system.h>
 #include <asm/div64.h>
@@ -531,8 +532,8 @@ out:
 static void suppress_loop(struct datapath *dp, struct sw_flow_actions *actions)
 {
        if (net_ratelimit())
-               printk(KERN_WARNING "%s: flow looped %d times, dropping\n",
-                      dp_name(dp), DP_MAX_LOOPS);
+               pr_warn("%s: flow looped %d times, dropping\n",
+                       dp_name(dp), DP_MAX_LOOPS);
        actions->n_actions = 0;
 }
 
@@ -542,40 +543,45 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
        struct datapath *dp = p->dp;
        struct dp_stats_percpu *stats;
        int stats_counter_off;
-       struct odp_flow_key key;
-       struct tbl_node *flow_node;
-       struct sw_flow *flow;
        struct sw_flow_actions *acts;
        struct loop_counter *loop;
        int error;
 
        OVS_CB(skb)->dp_port = p;
 
-       /* Extract flow from 'skb' into 'key'. */
-       error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key);
-       if (unlikely(error)) {
-               kfree_skb(skb);
-               return;
-       }
+       if (!OVS_CB(skb)->flow) {
+               struct odp_flow_key key;
+               struct tbl_node *flow_node;
+               bool is_frag;
 
-       if (OVS_CB(skb)->is_frag && dp->drop_frags) {
-               kfree_skb(skb);
-               stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
-               goto out;
-       }
+               /* Extract flow from 'skb' into 'key'. */
+               error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key, &is_frag);
+               if (unlikely(error)) {
+                       kfree_skb(skb);
+                       return;
+               }
 
-       /* Look up flow. */
-       flow_node = tbl_lookup(rcu_dereference(dp->table), &key, flow_hash(&key), flow_cmp);
-       if (unlikely(!flow_node)) {
-               dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
-               stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
-               goto out;
+               if (is_frag && dp->drop_frags) {
+                       kfree_skb(skb);
+                       stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
+                       goto out;
+               }
+
+               /* Look up flow. */
+               flow_node = tbl_lookup(rcu_dereference(dp->table), &key,
+                                       flow_hash(&key), flow_cmp);
+               if (unlikely(!flow_node)) {
+                       dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
+                       stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
+                       goto out;
+               }
+
+               OVS_CB(skb)->flow = flow_cast(flow_node);
        }
 
-       flow = flow_cast(flow_node);
-       flow_used(flow, skb);
+       flow_used(OVS_CB(skb)->flow, skb);
 
-       acts = rcu_dereference(flow->sf_acts);
+       acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
 
        /* Check whether we've looped too much. */
        loop = &get_cpu_var(dp_loop_counters).counters[!!in_interrupt()];
@@ -587,7 +593,8 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
        }
 
        /* Execute actions. */
-       execute_actions(dp, skb, &key, acts->actions, acts->n_actions, GFP_ATOMIC);
+       execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions,
+                       acts->n_actions, GFP_ATOMIC);
        stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
 
        /* Check whether sub-actions looped too much. */
@@ -645,9 +652,9 @@ int vswitch_skb_checksum_setup(struct sk_buff *skb)
                break;
        default:
                if (net_ratelimit())
-                       printk(KERN_ERR "Attempting to checksum a non-"
-                              "TCP/UDP packet, dropping a protocol"
-                              " %d packet", iph->protocol);
+                       pr_err("Attempting to checksum a non-TCP/UDP packet, "
+                              "dropping a protocol %d packet",
+                              iph->protocol);
                goto out;
        }
 
@@ -750,11 +757,10 @@ void compute_ip_summed(struct sk_buff *skb, bool xmit)
                break;
 #endif
        default:
-               printk(KERN_ERR "openvswitch: unknown checksum type %d\n",
-                      skb->ip_summed);
+               pr_err("unknown checksum type %d\n", skb->ip_summed);
                /* None seems the safest... */
                OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
-       }       
+       }
 
 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
        /* Xen has a special way of representing CHECKSUM_PARTIAL on older
@@ -1049,12 +1055,12 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
                }
 
                /* Allocate flow. */
-               error = -ENOMEM;
-               flow = kmem_cache_alloc(flow_cache, GFP_KERNEL);
-               if (flow == NULL)
+               flow = flow_alloc();
+               if (IS_ERR(flow)) {
+                       error = PTR_ERR(flow);
                        goto error;
+               }
                flow->key = uf->flow.key;
-               spin_lock_init(&flow->lock);
                clear_stats(flow);
 
                /* Obtain actions. */
@@ -1109,7 +1115,8 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
 error_free_flow_acts:
        kfree(flow->sf_acts);
 error_free_flow:
-       kmem_cache_free(flow_cache, flow);
+       flow->sf_acts = NULL;
+       flow_put(flow);
 error:
        return error;
 }
@@ -1319,16 +1326,18 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
        struct sk_buff *skb;
        struct sw_flow_actions *actions;
        struct ethhdr *eth;
+       bool is_frag;
        int err;
 
        err = -EINVAL;
        if (execute->length < ETH_HLEN || execute->length > 65535)
                goto error;
 
-       err = -ENOMEM;
        actions = flow_actions_alloc(execute->n_actions);
-       if (!actions)
+       if (IS_ERR(actions)) {
+               err = PTR_ERR(actions);
                goto error;
+       }
 
        err = -EFAULT;
        if (copy_from_user(actions->actions, execute->actions,
@@ -1365,7 +1374,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
        else
                skb->protocol = htons(ETH_P_802_2);
 
-       err = flow_extract(skb, execute->in_port, &key);
+       err = flow_extract(skb, execute->in_port, &key, &is_frag);
        if (err)
                goto error_free_skb;
 
@@ -2283,7 +2292,7 @@ ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
        }
 success:
        copy_bytes = tot_copy_bytes = min_t(size_t, skb->len, nbytes);
-       
+
        retval = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                if (copy_bytes == skb->len) {