datapath: Convert ODP_FLOW_* and ODP_EXECUTE to put dp_idx into message.
authorBen Pfaff <blp@nicira.com>
Wed, 19 Jan 2011 00:54:27 +0000 (16:54 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 28 Jan 2011 05:08:40 +0000 (21:08 -0800)
When the datapath moves to the Netlink protocol it won't have a minor
number to use, so we have to put the dp_idx in the message.

This also changes the kernel implementation of ODP_FLOW_FLUSH to do the
datapath locking inside flush_flows() instead of inside openvswitch_ioctl()
but doesn't change that command's userspace interface, which still passes
a datapath number as the ioctl argument.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
datapath/datapath.c
datapath/odp-compat.h
include/openvswitch/datapath-protocol.h
lib/dpif-linux.c

index 04d8bbd9955ada601977d6162f626d5f8ab2823f..f6a2824c5a25de7fb7442a09970d343ad82c1823 100644 (file)
@@ -642,20 +642,34 @@ err:
        return err;
 }
 
-static int flush_flows(struct datapath *dp)
+static int flush_flows(int dp_idx)
 {
-       struct tbl *old_table = get_table_protected(dp);
+       struct tbl *old_table;
        struct tbl *new_table;
+       struct datapath *dp;
+       int err;
+
+       dp = get_dp_locked(dp_idx);
+       err = -ENODEV;
+       if (!dp)
+               goto exit;
 
+       old_table = get_table_protected(dp);
        new_table = tbl_create(TBL_MIN_BUCKETS);
+       err = -ENOMEM;
        if (!new_table)
-               return -ENOMEM;
+               goto exit_unlock;
 
        rcu_assign_pointer(dp->table, new_table);
 
        tbl_deferred_destroy(old_table, flow_free_tbl);
 
-       return 0;
+       err = 0;
+
+exit_unlock:
+       mutex_unlock(&dp->mutex);
+exit:
+       return err;
 }
 
 static int validate_actions(const struct nlattr *actions, u32 actions_len)
@@ -906,24 +920,29 @@ error:
        return error;
 }
 
-static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
+static int put_flow(struct odp_flow_put __user *ufp)
 {
        struct odp_flow_stats stats;
        struct odp_flow_put uf;
+       struct datapath *dp;
        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;
+       dp = get_dp_locked(uf.flow.dp_idx);
+       if (!dp)
+               return -ENODEV;
 
-       if (copy_to_user(&ufp->flow.stats, &stats,
-                        sizeof(struct odp_flow_stats)))
-               return -EFAULT;
+       error = do_put_flow(dp, &uf, &stats);
+       if (!error) {
+               if (copy_to_user(&ufp->flow.stats, &stats,
+                                sizeof(struct odp_flow_stats)))
+                       error = -EFAULT;
+       }
+       mutex_unlock(&dp->mutex);
 
-       return 0;
+       return error;
 }
 
 static int do_answer_query(struct datapath *dp, struct sw_flow *flow,
@@ -993,90 +1012,110 @@ static struct sw_flow *do_del_flow(struct datapath *dp, const struct nlattr __us
        return flow_cast(flow_node);
 }
 
-static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
+static int del_flow(struct odp_flow __user *ufp)
 {
        struct sw_flow *flow;
+       struct datapath *dp;
        struct odp_flow uf;
        int error;
 
        if (copy_from_user(&uf, ufp, sizeof(uf)))
                return -EFAULT;
 
+       dp = get_dp_locked(uf.dp_idx);
+       if (!dp)
+               return -ENODEV;
+
        flow = do_del_flow(dp, (const struct nlattr __force __user *)uf.key, uf.key_len);
-       if (IS_ERR(flow))
-               return PTR_ERR(flow);
+       error = PTR_ERR(flow);
+       if (!IS_ERR(flow)) {
+               error = answer_query(dp, flow, ufp);
+               flow_deferred_free(flow);
+       }
+       mutex_unlock(&dp->mutex);
 
-       error = answer_query(dp, flow, ufp);
-       flow_deferred_free(flow);
        return error;
 }
 
-static int query_flow(struct datapath *dp, struct odp_flow __user *uflow)
+static int query_flow(struct odp_flow __user *uflow)
 {
-       struct tbl *table = get_table_protected(dp);
        struct tbl_node *flow_node;
        struct sw_flow_key key;
        struct odp_flow flow;
+       struct datapath *dp;
        int error;
 
        if (copy_from_user(&flow, uflow, sizeof(flow)))
                return -EFAULT;
 
-       error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len);
-       if (error)
-               return error;
-
-       flow_node = tbl_lookup(table, &flow.key, flow_hash(&key), flow_cmp);
-       if (!flow_node)
-               return -ENOENT;
-       return answer_query(dp, flow_cast(flow_node), uflow);
-}
-
-static struct sw_flow *do_dump_flow(struct datapath *dp, u32 __user *state)
-{
-       struct tbl *table = get_table_protected(dp);
-       struct tbl_node *tbl_node;
-       u32 bucket, obj;
-
-       if (get_user(bucket, &state[0]) || get_user(obj, &state[1]))
-               return ERR_PTR(-EFAULT);
-
-       tbl_node = tbl_next(table, &bucket, &obj);
+       dp = get_dp_locked(flow.dp_idx);
+       if (!dp)
+               return -ENODEV;
 
-       if (put_user(bucket, &state[0]) || put_user(obj, &state[1]))
-               return ERR_PTR(-EFAULT);
+       error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len);
+       if (!error) {
+               struct tbl *table = get_table_protected(dp);
+               flow_node = tbl_lookup(table, &flow.key, flow_hash(&key), flow_cmp);
+               if (flow_node)
+                       error = answer_query(dp, flow_cast(flow_node), uflow);
+               else
+                       error = -ENOENT;
+       }
+       mutex_unlock(&dp->mutex);
 
-       return tbl_node ? flow_cast(tbl_node) : NULL;
+       return error;
 }
 
-static int dump_flow(struct datapath *dp, struct odp_flow_dump __user *udumpp)
+static int dump_flow(struct odp_flow_dump __user *udump)
 {
-       struct odp_flow __user *uflowp;
+       struct odp_flow __user *uflow;
        struct nlattr __user *ukey;
+       struct tbl_node *tbl_node;
+       struct odp_flow_dump dump;
        struct sw_flow *flow;
+       struct datapath *dp;
+       struct tbl *table;
        u32 key_len;
+       int err;
 
-       flow = do_dump_flow(dp, udumpp->state);
-       if (IS_ERR(flow))
-               return PTR_ERR(flow);
+       err = -EFAULT;
+       if (copy_from_user(&dump, udump, sizeof(struct odp_flow_dump)))
+               goto exit;
+       uflow = (struct odp_flow __user __force *)dump.flow;
 
-       if (get_user(uflowp, (struct odp_flow __user *__user*)&udumpp->flow))
-               return -EFAULT;
+       dp = get_dp_locked(dump.dp_idx);
+       err = -ENODEV;
+       if (!dp)
+               goto exit;
 
-       if (!flow)
-               return put_user(0, &uflowp->key_len);
+       table = get_table_protected(dp);
+       tbl_node = tbl_next(table, &dump.state[0], &dump.state[1]);
+       if (!tbl_node) {
+               err = put_user(0, &uflow->key_len);
+               goto exit_unlock;
+       }
+       flow = flow_cast(tbl_node);
 
-       if (get_user(ukey, (struct nlattr __user * __user*)&uflowp->key) ||
-           get_user(key_len, &uflowp->key_len))
-               return -EFAULT;
+       err = -EFAULT;
+       if (copy_to_user(udump->state, dump.state, 2 * sizeof(uint32_t)) ||
+           get_user(ukey, (struct nlattr __user * __user*)&uflow->key) ||
+           get_user(key_len, &uflow->key_len))
+               goto exit_unlock;
 
        key_len = flow_copy_to_user(ukey, &flow->key, key_len);
+       err = key_len;
        if (key_len < 0)
-               return key_len;
-       if (put_user(key_len, &uflowp->key_len))
-               return -EFAULT;
+               goto exit_unlock;
+       err = -EFAULT;
+       if (put_user(key_len, &uflow->key_len))
+               goto exit_unlock;
+
+       err = answer_query(dp, flow, uflow);
 
-       return answer_query(dp, flow, uflowp);
+exit_unlock:
+       mutex_unlock(&dp->mutex);
+exit:
+       return err;
 }
 
 static int do_execute(struct datapath *dp, const struct odp_execute *execute)
@@ -1148,14 +1187,22 @@ error:
        return err;
 }
 
-static int execute_packet(struct datapath *dp, const struct odp_execute __user *executep)
+static int execute_packet(const struct odp_execute __user *executep)
 {
        struct odp_execute execute;
+       struct datapath *dp;
+       int error;
 
        if (copy_from_user(&execute, executep, sizeof(execute)))
                return -EFAULT;
 
-       return do_execute(dp, &execute);
+       dp = get_dp_locked(execute.dp_idx);
+       if (!dp)
+               return -ENODEV;
+       error = do_execute(dp, &execute);
+       mutex_unlock(&dp->mutex);
+
+       return error;
 }
 
 static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
@@ -1667,6 +1714,30 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
        case ODP_VPORT_DUMP:
                err = dump_vport((struct odp_vport __user *)argp);
                goto exit;
+
+       case ODP_FLOW_FLUSH:
+               err = flush_flows(argp);
+               goto exit;
+
+       case ODP_FLOW_PUT:
+               err = put_flow((struct odp_flow_put __user *)argp);
+               goto exit;
+
+       case ODP_FLOW_DEL:
+               err = del_flow((struct odp_flow __user *)argp);
+               goto exit;
+
+       case ODP_FLOW_GET:
+               err = query_flow((struct odp_flow __user *)argp);
+               goto exit;
+
+       case ODP_FLOW_DUMP:
+               err = dump_flow((struct odp_flow_dump __user *)argp);
+               goto exit;
+
+       case ODP_EXECUTE:
+               err = execute_packet((struct odp_execute __user *)argp);
+               goto exit;
        }
 
        dp = get_dp_locked(dp_idx);
@@ -1719,30 +1790,6 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                        dp->sflow_probability = sflow_probability;
                break;
 
-       case ODP_FLOW_FLUSH:
-               err = flush_flows(dp);
-               break;
-
-       case ODP_FLOW_PUT:
-               err = put_flow(dp, (struct odp_flow_put __user *)argp);
-               break;
-
-       case ODP_FLOW_DEL:
-               err = del_flow(dp, (struct odp_flow __user *)argp);
-               break;
-
-       case ODP_FLOW_GET:
-               err = query_flow(dp, (struct odp_flow __user *)argp);
-               break;
-
-       case ODP_FLOW_DUMP:
-               err = dump_flow(dp, (struct odp_flow_dump __user *)argp);
-               break;
-
-       case ODP_EXECUTE:
-               err = execute_packet(dp, (struct odp_execute __user *)argp);
-               break;
-
        default:
                err = -ENOIOCTLCMD;
                break;
@@ -1780,27 +1827,33 @@ static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow _
        return 0;
 }
 
-static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __user *ufp)
+static int compat_put_flow(struct compat_odp_flow_put __user *ufp)
 {
        struct odp_flow_stats stats;
-       struct odp_flow_put fp;
+       struct odp_flow_put uf;
+       struct datapath *dp;
        int error;
 
-       if (compat_get_flow(&fp.flow, &ufp->flow) ||
-           get_user(fp.flags, &ufp->flags))
+       if (compat_get_flow(&uf.flow, &ufp->flow) ||
+           get_user(uf.flags, &ufp->flags))
                return -EFAULT;
 
-       error = do_put_flow(dp, &fp, &stats);
-       if (error)
-               return error;
+       dp = get_dp_locked(uf.flow.dp_idx);
+       if (!dp)
+               return -ENODEV;
 
-       if (copy_to_user(&ufp->flow.stats, &stats,
-                        sizeof(struct odp_flow_stats)))
-               return -EFAULT;
+       error = do_put_flow(dp, &uf, &stats);
+       if (!error) {
+               if (copy_to_user(&ufp->flow.stats, &stats,
+                                sizeof(struct odp_flow_stats)))
+                       error = -EFAULT;
+       }
+       mutex_unlock(&dp->mutex);
 
-       return 0;
+       return error;
 }
 
+
 static int compat_answer_query(struct datapath *dp, struct sw_flow *flow,
                               struct compat_odp_flow __user *ufp)
 {
@@ -1813,84 +1866,124 @@ static int compat_answer_query(struct datapath *dp, struct sw_flow *flow,
                               compat_ptr(actions), &ufp->actions_len);
 }
 
-static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *ufp)
+static int compat_del_flow(struct compat_odp_flow __user *ufp)
 {
        struct sw_flow *flow;
+       struct datapath *dp;
        struct odp_flow uf;
        int error;
 
        if (compat_get_flow(&uf, ufp))
                return -EFAULT;
 
+       dp = get_dp_locked(uf.dp_idx);
+       if (!dp)
+               return -ENODEV;
+
        flow = do_del_flow(dp, (const struct nlattr __force __user *)uf.key, uf.key_len);
-       if (IS_ERR(flow))
-               return PTR_ERR(flow);
+       error = PTR_ERR(flow);
+       if (!IS_ERR(flow)) {
+               error = compat_answer_query(dp, flow, ufp);
+               flow_deferred_free(flow);
+       }
+       mutex_unlock(&dp->mutex);
 
-       error = compat_answer_query(dp, flow, ufp);
-       flow_deferred_free(flow);
        return error;
 }
 
-static int compat_query_flow(struct datapath *dp, struct compat_odp_flow __user *uflow)
+static int compat_query_flow(struct compat_odp_flow __user *uflow)
 {
-       struct tbl *table = get_table_protected(dp);
        struct tbl_node *flow_node;
        struct sw_flow_key key;
        struct odp_flow flow;
+       struct datapath *dp;
        int error;
 
        if (compat_get_flow(&flow, uflow))
                return -EFAULT;
 
+       dp = get_dp_locked(flow.dp_idx);
+       if (!dp)
+               return -ENODEV;
+
        error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len);
-       if (error)
-               return error;
+       if (!error) {
+               struct tbl *table = get_table_protected(dp);
+               flow_node = tbl_lookup(table, &flow.key, flow_hash(&key), flow_cmp);
+               if (flow_node)
+                       error = compat_answer_query(dp, flow_cast(flow_node), uflow);
+               else
+                       error = -ENOENT;
+       }
+       mutex_unlock(&dp->mutex);
 
-       flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp);
-       if (!flow_node)
-               return -ENOENT;
-       return compat_answer_query(dp, flow_cast(flow_node), uflow);
+       return error;
 }
 
-static int compat_dump_flow(struct datapath *dp, struct compat_odp_flow_dump __user *udumpp)
+static int compat_dump_flow(struct compat_odp_flow_dump __user *udump)
 {
-       struct compat_odp_flow __user *uflowp;
-       compat_uptr_t compat_ufp;
+       struct compat_odp_flow __user *uflow;
+       struct nlattr __user *ukey;
+       struct tbl_node *tbl_node;
+       struct compat_odp_flow_dump dump;
        struct sw_flow *flow;
-       compat_uptr_t ukey;
+       compat_uptr_t ukey32;
+       struct datapath *dp;
+       struct tbl *table;
        u32 key_len;
+       int err;
 
-       flow = do_dump_flow(dp, udumpp->state);
-       if (IS_ERR(flow))
-               return PTR_ERR(flow);
+       err = -EFAULT;
+       if (copy_from_user(&dump, udump, sizeof(struct compat_odp_flow_dump)))
+               goto exit;
+       uflow =compat_ptr(dump.flow);
 
-       if (get_user(compat_ufp, &udumpp->flow))
-               return -EFAULT;
-       uflowp = compat_ptr(compat_ufp);
+       dp = get_dp_locked(dump.dp_idx);
+       err = -ENODEV;
+       if (!dp)
+               goto exit;
 
-       if (!flow)
-               return put_user(0, &uflowp->key_len);
+       table = get_table_protected(dp);
+       tbl_node = tbl_next(table, &dump.state[0], &dump.state[1]);
+       if (!tbl_node) {
+               err = put_user(0, &uflow->key_len);
+               goto exit_unlock;
+       }
+       flow = flow_cast(tbl_node);
 
-       if (get_user(ukey, &uflowp->key) ||
-           get_user(key_len, &uflowp->key_len))
-               return -EFAULT;
+       err = -EFAULT;
+       if (copy_to_user(udump->state, dump.state, 2 * sizeof(uint32_t)) ||
+           get_user(ukey32, &uflow->key) ||
+           get_user(key_len, &uflow->key_len))
+               goto exit_unlock;
+       ukey = compat_ptr(ukey32);
 
-       key_len = flow_copy_to_user(compat_ptr(ukey), &flow->key, key_len);
+       key_len = flow_copy_to_user(ukey, &flow->key, key_len);
+       err = key_len;
        if (key_len < 0)
-               return key_len;
-       if (put_user(key_len, &uflowp->key_len))
-               return -EFAULT;
+               goto exit_unlock;
+       err = -EFAULT;
+       if (put_user(key_len, &uflow->key_len))
+               goto exit_unlock;
+
+       err = compat_answer_query(dp, flow, uflow);
 
-       return compat_answer_query(dp, flow, uflowp);
+exit_unlock:
+       mutex_unlock(&dp->mutex);
+exit:
+       return err;
 }
 
-static int compat_execute(struct datapath *dp, const struct compat_odp_execute __user *uexecute)
+static int compat_execute(const struct compat_odp_execute __user *uexecute)
 {
        struct odp_execute execute;
        compat_uptr_t actions;
        compat_uptr_t data;
+       struct datapath *dp;
+       int error;
 
        if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_odp_execute)) ||
+           __get_user(execute.dp_idx, &uexecute->dp_idx) ||
            __get_user(actions, &uexecute->actions) ||
            __get_user(execute.actions_len, &uexecute->actions_len) ||
            __get_user(data, &uexecute->data) ||
@@ -1900,15 +1993,17 @@ static int compat_execute(struct datapath *dp, const struct compat_odp_execute _
        execute.actions = (struct nlattr __force *)compat_ptr(actions);
        execute.data = (const void __force *)compat_ptr(data);
 
-       return do_execute(dp, &execute);
+       dp = get_dp_locked(execute.dp_idx);
+       if (!dp)
+               return -ENODEV;
+       error = do_execute(dp, &execute);
+       mutex_unlock(&dp->mutex);
+
+       return error;
 }
 
 static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned long argp)
 {
-       int dp_idx = iminor(f->f_dentry->d_inode);
-       struct datapath *dp;
-       int err;
-
        switch (cmd) {
        case ODP_DP_DESTROY:
        case ODP_FLOW_FLUSH:
@@ -1930,41 +2025,25 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
        case ODP_GET_SFLOW_PROBABILITY:
                /* Ioctls that just need their pointer argument extended. */
                return openvswitch_ioctl(f, cmd, (unsigned long)compat_ptr(argp));
-       }
-
-       dp = get_dp_locked(dp_idx);
-       err = -ENODEV;
-       if (!dp)
-               goto exit;
 
-       switch (cmd) {
        case ODP_FLOW_PUT32:
-               err = compat_put_flow(dp, compat_ptr(argp));
-               break;
+               return compat_put_flow(compat_ptr(argp));
 
        case ODP_FLOW_DEL32:
-               err = compat_del_flow(dp, compat_ptr(argp));
-               break;
+               return compat_del_flow(compat_ptr(argp));
 
        case ODP_FLOW_GET32:
-               err = compat_query_flow(dp, compat_ptr(argp));
-               break;
+               return compat_query_flow(compat_ptr(argp));
 
        case ODP_FLOW_DUMP32:
-               err = compat_dump_flow(dp, compat_ptr(argp));
-               break;
+               return compat_dump_flow(compat_ptr(argp));
 
        case ODP_EXECUTE32:
-               err = compat_execute(dp, compat_ptr(argp));
-               break;
+               return compat_execute(compat_ptr(argp));
 
        default:
-               err = -ENOIOCTLCMD;
-               break;
+               return -ENOIOCTLCMD;
        }
-       mutex_unlock(&dp->mutex);
-exit:
-       return err;
 }
 #endif
 
index bccfaf9da485ece097d6ecd61f7bfbfe9a4394eb..ae997e6776fecdfc1844660ddc30411ee2d87450 100644 (file)
@@ -23,6 +23,7 @@
 #define ODP_FLOW_DEL32         _IOWR('O', 17, struct compat_odp_flow)
 
 struct compat_odp_flow {
+       uint32_t dp_idx;
        struct odp_flow_stats stats;
        compat_uptr_t key;
        u32 key_len;
@@ -36,11 +37,14 @@ struct compat_odp_flow_put {
 };
 
 struct compat_odp_flow_dump {
+       uint32_t dp_idx;
        compat_uptr_t flow;
        uint32_t state[2];
 };
 
 struct compat_odp_execute {
+       uint32_t dp_idx;
+
        compat_uptr_t actions;
        u32 actions_len;
 
index 0078874ff891a93cf075fede0399d7ee4ab0f935..cf81cb31c7ca8027f31f3eab194afd77af08c22f 100644 (file)
@@ -272,6 +272,7 @@ struct odp_key_arp {
 };
 
 struct odp_flow {
+    uint32_t dp_idx;
     struct odp_flow_stats stats;
     struct nlattr *key;
     uint32_t key_len;
@@ -301,6 +302,7 @@ struct odp_flow_put {
  * unspecified.
  */
 struct odp_flow_dump {
+       uint32_t dp_idx;
        struct odp_flow *flow;
        uint32_t state[2];
 };
@@ -329,6 +331,8 @@ enum odp_action_type {
 #define ODPAT_MAX (__ODPAT_MAX - 1)
 
 struct odp_execute {
+    uint32_t dp_idx;
+
     struct nlattr *actions;
     uint32_t actions_len;
 
index d60950b6b7e8136f9cfffbf431800db1c3fd430a..3c11be2ce1f980fd9235416280d1a648b44e7cb3 100644 (file)
@@ -377,7 +377,8 @@ dpif_linux_get_max_ports(const struct dpif *dpif OVS_UNUSED)
 static int
 dpif_linux_flow_flush(struct dpif *dpif_)
 {
-    return do_ioctl(dpif_, ODP_FLOW_FLUSH, NULL);
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    return ioctl(dpif->fd, ODP_FLOW_FLUSH, dpif->minor) ? errno : 0;
 }
 
 struct dpif_linux_port_state {
@@ -474,11 +475,13 @@ dpif_linux_flow_get(const struct dpif *dpif_,
                     const struct nlattr *key, size_t key_len,
                     struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct ofpbuf *actions = NULL;
     struct odp_flow odp_flow;
     int error;
 
     memset(&odp_flow, 0, sizeof odp_flow);
+    odp_flow.dp_idx = dpif->minor;
     odp_flow.key = (struct nlattr *) key;
     odp_flow.key_len = key_len;
     if (actionsp) {
@@ -510,10 +513,12 @@ dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags,
                     const struct nlattr *actions, size_t actions_len,
                     struct dpif_flow_stats *stats)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct odp_flow_put put;
     int error;
 
     memset(&put, 0, sizeof put);
+    put.flow.dp_idx = dpif->minor;
     put.flow.key = (struct nlattr *) key;
     put.flow.key_len = key_len;
     put.flow.actions = (struct nlattr *) actions;
@@ -540,10 +545,12 @@ dpif_linux_flow_del(struct dpif *dpif_,
                     const struct nlattr *key, size_t key_len,
                     struct dpif_flow_stats *stats)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct odp_flow odp_flow;
     int error;
 
     memset(&odp_flow, 0, sizeof odp_flow);
+    odp_flow.dp_idx = dpif->minor;
     odp_flow.key = (struct nlattr *) key;
     odp_flow.key_len = key_len;
     error = do_ioctl(dpif_, ODP_FLOW_DEL, &odp_flow);
@@ -562,11 +569,13 @@ struct dpif_linux_flow_state {
 };
 
 static int
-dpif_linux_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep)
+dpif_linux_flow_dump_start(const struct dpif *dpif_, void **statep)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct dpif_linux_flow_state *state;
 
     *statep = state = xmalloc(sizeof *state);
+    state->dump.dp_idx = dpif->minor;
     state->dump.state[0] = 0;
     state->dump.state[1] = 0;
     state->dump.flow = &state->flow;
@@ -624,8 +633,11 @@ dpif_linux_execute(struct dpif *dpif_,
                    const struct nlattr *actions, size_t actions_len,
                    const struct ofpbuf *buf)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct odp_execute execute;
+
     memset(&execute, 0, sizeof execute);
+    execute.dp_idx = dpif->minor;
     execute.actions = (struct nlattr *) actions;
     execute.actions_len = actions_len;
     execute.data = buf->data;