- return 0;
-
-error_free_flow_acts:
- kfree(acts);
-error_free_flow:
- flow->sf_acts = NULL;
- flow_put(flow);
-error:
- return error;
-}
-
-static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
-{
- struct odp_flow_stats stats;
- struct odp_flow_put uf;
- int error;
-
- if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put)))
- return -EFAULT;
-
- error = do_put_flow(dp, &uf, &stats);
- if (error)
- return error;
-
- if (copy_to_user(&ufp->flow.stats, &stats,
- sizeof(struct odp_flow_stats)))
- return -EFAULT;
-
- return 0;
-}
-
-static int do_answer_query(struct datapath *dp, struct sw_flow *flow,
- u32 query_flags,
- struct odp_flow_stats __user *ustats,
- struct nlattr __user *actions,
- u32 __user *actions_lenp)
-{
- struct sw_flow_actions *sf_acts;
- struct odp_flow_stats stats;
- u32 actions_len;
-
- spin_lock_bh(&flow->lock);
- get_stats(flow, &stats);
- if (query_flags & ODPFF_ZERO_TCP_FLAGS)
- flow->tcp_flags = 0;
-
- spin_unlock_bh(&flow->lock);
-
- if (copy_to_user(ustats, &stats, sizeof(struct odp_flow_stats)) ||
- get_user(actions_len, actions_lenp))
- return -EFAULT;
-
- if (!actions_len)
- return 0;
-
- sf_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_is_held(&dp->mutex));
- if (put_user(sf_acts->actions_len, actions_lenp) ||
- (actions && copy_to_user(actions, sf_acts->actions,
- min(sf_acts->actions_len, actions_len))))
- return -EFAULT;
-
- return 0;
-}
-
-static int answer_query(struct datapath *dp, struct sw_flow *flow,
- u32 query_flags, struct odp_flow __user *ufp)
-{
- struct nlattr __user *actions;
-
- if (get_user(actions, (struct nlattr __user * __user *)&ufp->actions))
- return -EFAULT;
-
- return do_answer_query(dp, flow, query_flags,
- &ufp->stats, actions, &ufp->actions_len);
-}
-
-static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key)
-{
- struct tbl *table = get_table_protected(dp);
- struct tbl_node *flow_node;
- int error;
-
- flow_node = tbl_lookup(table, key, flow_hash(key), flow_cmp);
- if (!flow_node)
- return ERR_PTR(-ENOENT);
-
- error = tbl_remove(table, flow_node);
- if (error)
- return ERR_PTR(error);
-
- /* XXX Returned flow_node's statistics might lose a few packets, since
- * other CPUs can be using this flow. We used to synchronize_rcu() to
- * make sure that we get completely accurate stats, but that blows our
- * performance, badly. */
- return flow_cast(flow_node);