- struct odp_flow uf;
- int error;
-
- if (copy_from_user(&uf, ufp, sizeof uf))
- return -EFAULT;
-
- flow = do_del_flow(dp, &uf.key);
- if (IS_ERR(flow))
- return PTR_ERR(flow);
-
- error = answer_query(flow, 0, ufp);
- flow_deferred_free(flow);
- return error;
-}
-
-static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
-{
- struct tbl *table = rcu_dereference(dp->table);
- u32 i;
-
- for (i = 0; i < flowvec->n_flows; i++) {
- struct odp_flow __user *ufp = (struct odp_flow __user *)&flowvec->flows[i];
- struct odp_flow uf;
- struct tbl_node *flow_node;
- int error;
-
- if (copy_from_user(&uf, ufp, sizeof uf))
- return -EFAULT;
-
- flow_node = tbl_lookup(table, &uf.key, flow_hash(&uf.key), flow_cmp);
- if (!flow_node)
- error = put_user(ENOENT, &ufp->stats.error);
- else
- error = answer_query(flow_cast(flow_node), uf.flags, ufp);
- if (error)
- return -EFAULT;
- }
- return flowvec->n_flows;
-}
-
-struct list_flows_cbdata {
- struct odp_flow __user *uflows;
- u32 n_flows;
- u32 listed_flows;
-};
-
-static int list_flow(struct tbl_node *node, void *cbdata_)
-{
- struct sw_flow *flow = flow_cast(node);
- struct list_flows_cbdata *cbdata = cbdata_;
- struct odp_flow __user *ufp = &cbdata->uflows[cbdata->listed_flows++];
- int error;
-
- if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
- return -EFAULT;
- error = answer_query(flow, 0, ufp);
- if (error)
- return error;
-
- if (cbdata->listed_flows >= cbdata->n_flows)
- return cbdata->listed_flows;
- return 0;
-}
-
-static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
-{
- struct list_flows_cbdata cbdata;
- int error;
-
- if (!flowvec->n_flows)
- return 0;
-
- cbdata.uflows = (struct odp_flow __user *)flowvec->flows;
- cbdata.n_flows = flowvec->n_flows;
- cbdata.listed_flows = 0;
-
- error = tbl_foreach(rcu_dereference(dp->table), list_flow, &cbdata);
- return error ? error : cbdata.listed_flows;
-}
-
-static int do_flowvec_ioctl(struct datapath *dp, unsigned long argp,
- int (*function)(struct datapath *,
- const struct odp_flowvec *))
-{
- struct odp_flowvec __user *uflowvec;
- struct odp_flowvec flowvec;
- int retval;
-
- uflowvec = (struct odp_flowvec __user *)argp;
- if (copy_from_user(&flowvec, uflowvec, sizeof flowvec))
- return -EFAULT;
-
- if (flowvec.n_flows > INT_MAX / sizeof(struct odp_flow))
- return -EINVAL;
-
- retval = function(dp, &flowvec);
- return (retval < 0 ? retval
- : retval == flowvec.n_flows ? 0
- : put_user(retval, &uflowvec->n_flows));
-}
-
-static int do_execute(struct datapath *dp, const struct odp_execute *execute)
-{
- struct odp_flow_key key;
- struct sk_buff *skb;
- struct sw_flow_actions *actions;