xenserver: Clear vlan.* from /etc/ovs-vswitchd.conf on boot too
[openvswitch] / datapath / datapath.c
index 5092ced013dba310710d952a32f2c95b89070e83..b0dbe7fc23604b449a992e067278b3713fc2a2b3 100644 (file)
@@ -850,7 +850,7 @@ static void clear_stats(struct sw_flow *flow)
 static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
 {
        struct odp_flow_put uf;
-       struct sw_flow *flow, **bucket;
+       struct sw_flow *flow;
        struct dp_table *table;
        struct odp_flow_stats stats;
        int error;
@@ -860,15 +860,10 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
                goto error;
        uf.flow.key.reserved = 0;
 
-retry:
        table = rcu_dereference(dp->table);
-       bucket = dp_table_lookup_for_insert(table, &uf.flow.key);
-       if (!bucket) {
-               /* No such flow, and the slots where it could go are full. */
-               error = uf.flags & ODPPF_CREATE ? -EFBIG : -ENOENT;
-               goto error;
-       } else if (!*bucket) {
-               /* No such flow, but we found an available slot for it. */
+       flow = dp_table_lookup(table, &uf.flow.key);
+       if (!flow) {
+               /* No such flow. */
                struct sw_flow_actions *acts;
 
                error = -ENOENT;
@@ -876,14 +871,15 @@ retry:
                        goto error;
 
                /* Expand table, if necessary, to make room. */
-               if (dp->n_flows * 4 >= table->n_buckets &&
-                   table->n_buckets < DP_MAX_BUCKETS) {
+               if (dp->n_flows >= table->n_buckets) {
+                       error = -ENOSPC;
+                       if (table->n_buckets >= DP_MAX_BUCKETS)
+                               goto error;
+
                        error = dp_table_expand(dp);
                        if (error)
                                goto error;
-
-                       /* The bucket's location has changed.  Try again. */
-                       goto retry;
+                       table = rcu_dereference(dp->table);
                }
 
                /* Allocate flow. */
@@ -903,12 +899,13 @@ retry:
                rcu_assign_pointer(flow->sf_acts, acts);
 
                /* Put flow in bucket. */
-               rcu_assign_pointer(*bucket, flow);
+               error = dp_table_insert(table, flow);
+               if (error)
+                       goto error_free_flow_acts;
                dp->n_flows++;
                memset(&stats, 0, sizeof(struct odp_flow_stats));
        } else {
                /* We found a matching flow. */
-               struct sw_flow *flow = *rcu_dereference(bucket);
                struct sw_flow_actions *old_acts, *new_acts;
                unsigned long int flags;
 
@@ -946,6 +943,8 @@ retry:
                return -EFAULT;
        return 0;
 
+error_free_flow_acts:
+       kfree(flow->sf_acts);
 error_free_flow:
        kmem_cache_free(flow_cache, flow);
 error:
@@ -1128,6 +1127,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
        struct odp_flow_key key;
        struct sk_buff *skb;
        struct sw_flow_actions *actions;
+       struct ethhdr *eth;
        int err;
 
        err = -EFAULT;
@@ -1167,6 +1167,17 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
                           execute.length))
                goto error_free_skb;
 
+       skb_reset_mac_header(skb);
+       eth = eth_hdr(skb);
+
+    /* Normally, setting the skb 'protocol' field would be handled by a
+     * call to eth_type_trans(), but it assumes there's a sending
+     * device, which we may not have. */
+       if (ntohs(eth->h_proto) >= 1536)
+               skb->protocol = eth->h_proto;
+       else
+               skb->protocol = htons(ETH_P_802_2);
+
        flow_extract(skb, execute.in_port, &key);
        err = execute_actions(dp, skb, &key, actions->actions,
                              actions->n_actions, GFP_KERNEL);
@@ -1188,8 +1199,8 @@ get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
        int i;
 
        stats.n_flows = dp->n_flows;
-       stats.cur_capacity = rcu_dereference(dp->table)->n_buckets * 2;
-       stats.max_capacity = DP_MAX_BUCKETS * 2;
+       stats.cur_capacity = rcu_dereference(dp->table)->n_buckets;
+       stats.max_capacity = DP_MAX_BUCKETS;
        stats.n_ports = dp->n_ports;
        stats.max_ports = DP_MAX_PORTS;
        stats.max_groups = DP_MAX_GROUPS;