datapath: Generalize flow creation and modification.
authorBen Pfaff <blp@nicira.com>
Mon, 4 May 2009 23:10:28 +0000 (16:10 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 4 May 2009 23:10:28 +0000 (16:10 -0700)
The ODP_FLOW_ADD and ODP_FLOW_SET_ACTS datapath commands can be usefully
generalized based on whether they should be allowed to create or modify
flows, or both, and whether they reset flow statistics when they modify
an existing flow.  This commit does so by merging them into a single
ODP_FLOW_PUT command and adding a set of flags.

In particular this is needed to allow flows to be reinstalled if it is
uncertain whether they have been externally deleted (e.g. with "dpctl
dp-del-flows") without requiring first reading the flow table (as
handle_odp_msg() wants to do), and to replace a flow's actions and reset
its statistics without first deleting it (as rule_update_actions() wants
to do).

Also renames some other datapath commands, for naming consistency.

Also adapts userspace to these changes.

datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
datapath/table.c
include/openflow/datapath-protocol.h
lib/dpif.c
lib/dpif.h
secchan/ofproto.c
utilities/dpctl.c

index 899ed495bf03fcb445ad46c4692e12274630c6f3..03afe3a7fb3f7e99c1b09d25a8dbfe5b7efd903d 100644 (file)
@@ -831,135 +831,152 @@ static int validate_actions(const struct sw_flow_actions *actions)
        return 0;
 }
 
-static int set_flow_actions(struct datapath *dp, struct odp_flow __user *ufp)
+static struct sw_flow_actions *get_actions(const struct odp_flow *flow)
 {
-       struct sw_flow_actions *new_acts, *old_acts;
-       struct sw_flow *flow;
-       struct odp_flow uf;
+       struct sw_flow_actions *actions;
        int error;
 
-       error = -EFAULT;
-       if (copy_from_user(&uf, ufp, sizeof uf))
+       actions = flow_actions_alloc(flow->n_actions);
+       error = PTR_ERR(actions);
+       if (IS_ERR(actions))
                goto error;
 
-       /* Get actions. */
-       new_acts = flow_actions_alloc(uf.n_actions);
-       error = -ENOMEM;
-       if (!new_acts)
-               goto error;
        error = -EFAULT;
-       if (copy_from_user(new_acts->actions, uf.actions,
-                          uf.n_actions * sizeof *uf.actions))
+       if (copy_from_user(actions->actions, flow->actions,
+                          flow->n_actions * sizeof(union odp_action)))
                goto error_free_actions;
-       error = validate_actions(new_acts);
+       error = validate_actions(actions);
        if (error)
                goto error_free_actions;
 
-       /* Replace actions. */
-       flow = dp_table_lookup(dp->table, &uf.key);
-       error = -ENOENT;
-       if (!flow)
-               goto error_free_actions;
-       old_acts = rcu_dereference(flow->sf_acts);
-       rcu_assign_pointer(flow->sf_acts, new_acts);
-       flow_deferred_free_acts(old_acts);
-
-       return 0;
+       return actions;
 
 error_free_actions:
-       kfree(new_acts);
+       kfree(actions);
 error:
-       return error;
+       return ERR_PTR(error);
 }
 
-static int put_stats(struct sw_flow *flow, struct __user odp_flow *ufp)
+static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats)
 {
-       struct odp_flow_stats stats;
-       unsigned long flags;
-
        if (flow->used.tv_sec) {
-               stats.used_sec = flow->used.tv_sec;
-               stats.used_nsec = flow->used.tv_nsec;
+               stats->used_sec = flow->used.tv_sec;
+               stats->used_nsec = flow->used.tv_nsec;
        } else {
-               stats.used_sec = 0;
-               stats.used_nsec = 0;
+               stats->used_sec = 0;
+               stats->used_nsec = 0;
        }
+       stats->n_packets = flow->packet_count;
+       stats->n_bytes = flow->byte_count;
+       stats->ip_tos = flow->ip_tos;
+       stats->tcp_flags = flow->tcp_flags;
+}
 
-       spin_lock_irqsave(&flow->lock, flags);
-       stats.n_packets = flow->packet_count;
-       stats.n_bytes = flow->byte_count;
-       stats.ip_tos = flow->ip_tos;
-       stats.tcp_flags = flow->tcp_flags;
-       spin_unlock_irqrestore(&flow->lock, flags);
-
-       return __copy_to_user(&ufp->stats, &stats, sizeof ufp->stats);
+static void clear_stats(struct sw_flow *flow)
+{
+       flow->used.tv_sec = flow->used.tv_nsec = 0;
+       flow->tcp_flags = 0;
+       flow->ip_tos = 0;
+       flow->packet_count = 0;
+       flow->byte_count = 0;
 }
 
-static int add_flow(struct datapath *dp, struct odp_flow __user *ufp)
+static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
 {
-       struct odp_flow uf;
+       struct odp_flow_put uf;
        struct sw_flow *flow, **bucket;
        struct dp_table *table;
-       struct sw_flow_actions *sf_acts;
+       struct odp_flow_stats stats;
        int error;
 
        error = -EFAULT;
-       if (copy_from_user(&uf, ufp, sizeof uf))
+       if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put)))
                goto error;
 
-       flow = flow_alloc(uf.n_actions);
-       if (flow == NULL)
+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 ? -EXFULL : -ENOENT;
                goto error;
-       sf_acts = rcu_dereference(flow->sf_acts);
+       } else if (!*bucket) {
+               /* No such flow, but we found an available slot for it. */
+               struct sw_flow_actions *acts;
 
-       /* Initialize flow. */
-       flow->key = uf.key;
-       if (copy_from_user(sf_acts->actions, uf.actions,
-                          uf.n_actions * sizeof *uf.actions))
-               goto error_free_flow;
-       error = validate_actions(sf_acts);
-       if (error)
-               goto error_free_flow;
+               error = -ENOENT;
+               if (!(uf.flags & ODPPF_CREATE))
+                       goto error;
 
-       flow->used.tv_sec = flow->used.tv_nsec = 0;
-       flow->tcp_flags = 0;
-       flow->ip_tos = 0;
-       spin_lock_init(&flow->lock);
-       flow->packet_count = 0;
-       flow->byte_count = 0;
+               /* Expand table, if necessary, to make room. */
+               if (dp->n_flows * 4 >= table->n_buckets &&
+                   table->n_buckets < DP_MAX_BUCKETS) {
+                       error = dp_table_expand(dp);
+                       if (error)
+                               goto error;
 
-       /* Add to table. */
-       table = rcu_dereference(dp->table);
-       if (dp->n_flows * 4 >= table->n_buckets &&
-           table->n_buckets < DP_MAX_BUCKETS) {
-               error = dp_table_expand(dp);
-               if (error)
+                       /* The bucket's location has changed.  Try again. */
+                       goto retry;
+               }
+
+               /* Allocate flow. */
+               flow = kmem_cache_alloc(flow_cache, GFP_KERNEL);
+               if (flow == NULL)
+                       goto error;
+               flow->key = uf.flow.key;
+               spin_lock_init(&flow->lock);
+               clear_stats(flow);
+
+               /* Obtain actions. */
+               acts = get_actions(&uf.flow);
+               error = PTR_ERR(acts);
+               if (IS_ERR(acts))
                        goto error_free_flow;
-               table = dp->table;
-       }
+               rcu_assign_pointer(flow->sf_acts, acts);
 
-       bucket = dp_table_lookup_for_insert(table, flow);
-       error = -EXFULL;
-       if (!bucket)
-               goto error_free_flow;
-       else if (!*bucket) {
-               error = 0;
+               /* Put flow in bucket. */
                rcu_assign_pointer(*bucket, flow);
                dp->n_flows++;
+               memset(&stats, 0, sizeof(struct odp_flow_stats));
        } else {
-               /* Replace 'old_flow' by 'flow'. */
-               struct sw_flow *old_flow = *rcu_dereference(bucket);
-               rcu_assign_pointer(*bucket, flow);
+               /* We found a matching flow. */
+               struct sw_flow *flow = *rcu_dereference(bucket);
+               struct sw_flow_actions *old_acts, *new_acts;
+               unsigned long int flags;
+
+               /* Bail out if we're not allowed to modify an existing flow. */
+               error = -EEXIST;
+               if (!(uf.flags & ODPPF_MODIFY))
+                       goto error;
 
-               /* XXX These 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. */
-               error = put_stats(old_flow, ufp) ? -EFAULT : 0;
-               flow_deferred_free(old_flow);
+               /* Swap actions. */
+               new_acts = get_actions(&uf.flow);
+               error = PTR_ERR(new_acts);
+               if (IS_ERR(new_acts))
+                       goto error;
+               old_acts = rcu_dereference(flow->sf_acts);
+               if (old_acts->n_actions != new_acts->n_actions ||
+                   memcmp(old_acts->actions, new_acts->actions,
+                          sizeof(union odp_action) * old_acts->n_actions)) {
+                       rcu_assign_pointer(flow->sf_acts, new_acts);
+                       flow_deferred_free_acts(old_acts);
+               } else {
+                       kfree(new_acts);
+               }
+
+               /* Fetch stats, then clear them if necessary. */
+               spin_lock_irqsave(&flow->lock, flags);
+               get_stats(flow, &stats);
+               if (uf.flags & ODPPF_ZERO_STATS)
+                       clear_stats(flow);
+               spin_unlock_irqrestore(&flow->lock, flags);
        }
 
-       return error;
+       /* Copy stats to userspace. */
+       if (__copy_to_user(&ufp->flow.stats, &stats,
+                          sizeof(struct odp_flow_stats)))
+               return -EFAULT;
+       return 0;
 
 error_free_flow:
        flow_free(flow);
@@ -994,7 +1011,14 @@ static int put_actions(const struct sw_flow *flow, struct odp_flow __user *ufp)
 
 static int answer_query(struct sw_flow *flow, struct odp_flow __user *ufp)
 {
-       if (put_stats(flow, ufp))
+       struct odp_flow_stats stats;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&flow->lock, flags);
+       get_stats(flow, &stats);
+       spin_unlock_irqrestore(&flow->lock, flags);
+
+       if (__copy_to_user(&ufp->stats, &stats, sizeof(struct odp_flow_stats)))
                return -EFAULT;
        return put_actions(flow, ufp);
 }
@@ -1438,21 +1462,17 @@ static long openflow_ioctl(struct file *f, unsigned int cmd,
                err = flush_flows(dp);
                break;
 
-       case ODP_FLOW_ADD:
-               err = add_flow(dp, (struct odp_flow __user *)argp);
-               break;
-
-       case ODP_FLOW_SET_ACTS:
-               err = set_flow_actions(dp, (struct odp_flow __user *)argp);
+       case ODP_FLOW_PUT:
+               err = put_flow(dp, (struct odp_flow_put __user *)argp);
                break;
 
        case ODP_FLOW_DEL:
-       case ODP_FLOW_QUERY:
+       case ODP_FLOW_GET:
                err = del_or_query_flow(dp, (struct odp_flow __user *)argp,
                                        cmd);
                break;
 
-       case ODP_FLOW_QUERY_MULTIPLE:
+       case ODP_FLOW_GET_MULTIPLE:
                err = do_flowvec_ioctl(dp, argp, query_multiple_flows);
                break;
 
index bb9ce0a331b9ba43e33276de4c5a81649456d573..71831ebd0911bfc3dbfc09e6670196d2380c5e3a 100644 (file)
@@ -109,8 +109,7 @@ extern int (*dp_del_if_hook)(struct net_bridge_port *p);
 struct dp_table *dp_table_create(unsigned int n_buckets);
 void dp_table_destroy(struct dp_table *, int free_flows);
 struct sw_flow *dp_table_lookup(struct dp_table *, const struct odp_flow_key *);
-struct sw_flow **dp_table_lookup_for_insert(struct dp_table *table,
-                                           struct sw_flow *target);
+struct sw_flow **dp_table_lookup_for_insert(struct dp_table *, const struct odp_flow_key *);
 int dp_table_delete(struct dp_table *, struct sw_flow *);
 int dp_table_expand(struct datapath *);
 int dp_table_flush(struct datapath *);
index 024b61cd0ead19d66bb6e71cd6093be0cf98c419..c9a6e9d01b0a264551c67443e8f4f78c3068f3bf 100644 (file)
@@ -96,36 +96,18 @@ struct sw_flow_actions *flow_actions_alloc(size_t n_actions)
        struct sw_flow_actions *sfa;
 
        if (n_actions > (PAGE_SIZE - sizeof *sfa) / sizeof(union odp_action))
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        sfa = kmalloc(sizeof *sfa + n_actions * sizeof(union odp_action),
                      GFP_KERNEL);
-       if (sfa)
-               sfa->n_actions = n_actions;
-       return sfa;
-}
-
-
-/* Allocates and returns a new flow with room for 'n_actions' actions.  Returns
- * the new flow or a null pointer on failure. */
-struct sw_flow *flow_alloc(size_t n_actions)
-{
-       struct sw_flow_actions *sfa;
-       struct sw_flow *flow;
-
-       sfa = flow_actions_alloc(n_actions);
        if (!sfa)
-               return NULL;
-
-       flow = kmem_cache_alloc(flow_cache, GFP_KERNEL);
-       if (flow)
-               rcu_assign_pointer(flow->sf_acts, sfa);
-       else
-               kfree(sfa);
+               return ERR_PTR(-ENOMEM);
 
-       return flow;
+       sfa->n_actions = n_actions;
+       return sfa;
 }
 
+
 /* Frees 'flow' immediately. */
 void flow_free(struct sw_flow *flow)
 {
index f44774fe1e0f2ea922e800007fa3c92e798b6975..5d3fd2601fafdaa134018922622ebdf85ca2937b 100644 (file)
@@ -32,8 +32,9 @@ struct sw_flow {
        u8 tcp_flags;           /* Union of seen TCP flags. */
 };
 
+extern struct kmem_cache *flow_cache;
+
 struct sw_flow_actions *flow_actions_alloc(size_t n_actions);
-struct sw_flow *flow_alloc(size_t n_actions);
 void flow_free(struct sw_flow *);
 void flow_deferred_free(struct sw_flow *);
 void flow_deferred_free_acts(struct sw_flow_actions *);
index 7890442d5840eed0a81a3fc66b67e05ec37d8c29..88aa7d2ad97914e958bf299b374baeaa5321aafc 100644 (file)
@@ -109,7 +109,8 @@ static u32 flow_hash1(const struct odp_flow_key *key)
        return jhash2((u32*)key, sizeof *key / sizeof(u32), 0x55555555);
 }
 
-static void find_buckets(struct dp_table *table, struct odp_flow_key *key,
+static void find_buckets(struct dp_table *table,
+                        const struct odp_flow_key *key,
                         struct sw_flow **buckets[2])
 {
        buckets[0] = find_bucket(table, table->flows[0], flow_hash0(key));
@@ -201,17 +202,18 @@ int dp_table_flush(struct datapath *dp)
 }
 
 struct sw_flow **
-dp_table_lookup_for_insert(struct dp_table *table, struct sw_flow *target)
+dp_table_lookup_for_insert(struct dp_table *table,
+                          const struct odp_flow_key *target)
 {
        struct sw_flow **buckets[2];
        struct sw_flow **empty_bucket = NULL;
        int i;
 
-       find_buckets(table, &target->key, buckets);
+       find_buckets(table, target, buckets);
        for (i = 0; i < 2; i++) {
                struct sw_flow *f = rcu_dereference(*buckets[i]);
                if (f) {
-                       if (!memcmp(&f->key, &target->key, sizeof f->key))
+                       if (!memcmp(&f->key, target, sizeof f->key))
                                return buckets[i];
                } else if (!empty_bucket)
                        empty_bucket = buckets[i];
index c65293cd8cd846956f8b48d16ba893de416ca7ee..cf5075ec8600c76b7a3cd7dab69df0cf89ad097c 100644 (file)
 #define ODP_PORT_GROUP_SET      _IOR('O', 11, struct odp_port_group)
 #define ODP_PORT_GROUP_GET      _IOWR('O', 12, struct odp_port_group)
 
-#define ODP_FLOW_FLUSH          _IO('O', 13)
-#define ODP_FLOW_ADD            _IOR('O', 14, struct odp_flow)
-#define ODP_FLOW_SET_ACTS       _IOR('O', 15, struct odp_flow)
-#define ODP_FLOW_DEL            _IOWR('O', 16, struct odp_flow)
-#define ODP_FLOW_QUERY          _IOWR('O', 17, struct odp_flow)
-#define ODP_FLOW_QUERY_MULTIPLE _IOWR('O', 18, struct odp_flowvec)
-#define ODP_FLOW_LIST           _IOWR('O', 19, struct odp_flowvec)
+#define ODP_FLOW_GET            _IOWR('O', 13, struct odp_flow)
+#define ODP_FLOW_GET_MULTIPLE   _IOWR('O', 14, struct odp_flowvec)
+#define ODP_FLOW_LIST           _IOWR('O', 15, struct odp_flowvec)
 
-#define ODP_EXECUTE             _IOR('O', 20, struct odp_execute)
+#define ODP_FLOW_FLUSH          _IO('O', 16)
+#define ODP_FLOW_PUT            _IOWR('O', 17, struct odp_flow)
+#define ODP_FLOW_DEL            _IOWR('O', 18, struct odp_flow)
 
-#define ODP_SNAT_ADD_PORT       _IOR('O', 21, struct odp_snat_config)
-#define ODP_SNAT_DEL_PORT       _IOR('O', 22, int)
+#define ODP_EXECUTE             _IOR('O', 19, struct odp_execute)
+
+#define ODP_SNAT_ADD_PORT       _IOR('O', 20, struct odp_snat_config)
+#define ODP_SNAT_DEL_PORT       _IOR('O', 21, int)
 
 struct odp_stats {
     /* Flows. */
@@ -169,6 +169,17 @@ struct odp_flow {
     __u32 n_actions;
 };
 
+/* Flags for ODP_FLOW_PUT. */
+#define ODPPF_CREATE        (1 << 0) /* Allow creating a new flow. */
+#define ODPPF_MODIFY        (1 << 1) /* Allow modifying an existing flow. */
+#define ODPPF_ZERO_STATS    (1 << 2) /* Zero the stats of an existing flow. */
+
+/* ODP_FLOW_PUT argument. */
+struct odp_flow_put {
+    struct odp_flow flow;
+    __u32 flags;
+};
+
 struct odp_flowvec {
     struct odp_flow *flows;
     int n_flows;
index 119b40c3cb877b8b3989d558b1e4dd3fb898f21b..0ff68a5a2fb4946d444f486bfd283b5e4fb3f336 100644 (file)
@@ -131,7 +131,7 @@ do_ioctl(const struct dpif *dpif, int cmd, const char *cmd_name,
     if (cmd_name) {
         if (error) {
             VLOG_WARN_RL(&error_rl, "dp%u: ioctl(%s) failed (%s)",
-                         dpif->minor, cmd_name, strerror(errno));
+                         dpif->minor, cmd_name, strerror(error));
         } else {
             VLOG_DBG_RL(&dpmsg_rl, "dp%u: ioctl(%s): success",
                         dpif->minor, cmd_name);
@@ -400,8 +400,21 @@ dpif_flow_flush(struct dpif *dpif)
     return do_ioctl(dpif, ODP_FLOW_FLUSH, "ODP_FLOW_FLUSH", NULL);
 }
 
+static enum vlog_level
+flow_message_log_level(int error)
+{
+    return error ? VLL_WARN : VLL_DBG;
+}
+
+static bool
+should_log_flow_message(int error)
+{
+    return !vlog_should_drop(THIS_MODULE, flow_message_log_level(error),
+                             error ? &error_rl : &dpmsg_rl);
+}
+
 static void
-log_flow_message(const struct dpif *dpif, enum vlog_level level, int error,
+log_flow_message(const struct dpif *dpif, int error,
                  const char *operation,
                  const flow_t *flow, const struct odp_flow_stats *stats,
                  const union odp_action *actions, size_t n_actions)
@@ -424,7 +437,7 @@ log_flow_message(const struct dpif *dpif, enum vlog_level level, int error,
         ds_put_cstr(&ds, ", actions:");
         format_odp_actions(&ds, actions, n_actions);
     }
-    vlog(THIS_MODULE, level, "%s", ds_cstr(&ds));
+    vlog(THIS_MODULE, flow_message_log_level(error), "%s", ds_cstr(&ds));
     ds_destroy(&ds);
 }
 
@@ -436,9 +449,8 @@ do_flow_ioctl(const struct dpif *dpif, int cmd, struct odp_flow *flow,
     if (error && show_stats) {
         flow->n_actions = 0;
     }
-    if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) {
-        log_flow_message(dpif, error ? VLL_WARN : VLL_DBG, error, operation,
-                         &flow->key,
+    if (should_log_flow_message(error)) {
+        log_flow_message(dpif, error, operation, &flow->key,
                          show_stats && !error ? &flow->stats : NULL,
                          flow->actions, flow->n_actions);
     }
@@ -446,22 +458,31 @@ do_flow_ioctl(const struct dpif *dpif, int cmd, struct odp_flow *flow,
 }
 
 int
-dpif_flow_add(struct dpif *dpif, struct odp_flow *flow)
-{
-    return do_flow_ioctl(dpif, ODP_FLOW_ADD, flow, "add flow", false);
-}
-
-int
-dpif_flow_set_actions(struct dpif *dpif, const struct odp_flow_key *key,
-                      const union odp_action *actions, size_t n_actions)
+dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put)
 {
-    struct odp_flow flow;
-
-    flow.key = *key;
-    flow.actions = (union odp_action *) actions;
-    flow.n_actions = n_actions;
-    return do_flow_ioctl(dpif, ODP_FLOW_SET_ACTS, &flow, "set flow actions",
-                         false);
+    int error = do_ioctl(dpif, ODP_FLOW_PUT, NULL, put);
+    if (should_log_flow_message(error)) {
+        struct ds operation = DS_EMPTY_INITIALIZER;
+        ds_put_cstr(&operation, "put");
+        if (put->flags & ODPPF_CREATE) {
+            ds_put_cstr(&operation, "[create]");
+        }
+        if (put->flags & ODPPF_MODIFY) {
+            ds_put_cstr(&operation, "[modify]");
+        }
+        if (put->flags & ODPPF_ZERO_STATS) {
+            ds_put_cstr(&operation, "[zero]");
+        }
+#define ODPPF_ALL (ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS)
+        if (put->flags & ~ODPPF_ALL) {
+            ds_put_format(&operation, "[%x]", put->flags & ~ODPPF_ALL);
+        }
+        log_flow_message(dpif, error, ds_cstr(&operation), &put->flow.key,
+                         !error ? &put->flow.stats : NULL,
+                         put->flow.actions, put->flow.n_actions);
+        ds_destroy(&operation);
+    }
+    return error;
 }
 
 int
@@ -473,16 +494,16 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
 }
 
 int
-dpif_flow_query(const struct dpif *dpif, struct odp_flow *flow)
+dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
 {
     check_rw_odp_flow(flow);
     memset(&flow->stats, 0, sizeof flow->stats);
-    return do_flow_ioctl(dpif, ODP_FLOW_QUERY, flow, "query flow", true);
+    return do_flow_ioctl(dpif, ODP_FLOW_GET, flow, "get flow", true);
 }
 
 int
-dpif_flow_query_multiple(const struct dpif *dpif,
-                         struct odp_flow flows[], size_t n)
+dpif_flow_get_multiple(const struct dpif *dpif,
+                       struct odp_flow flows[], size_t n)
 {
     struct odp_flowvec fv;
     size_t i;
@@ -492,7 +513,7 @@ dpif_flow_query_multiple(const struct dpif *dpif,
     for (i = 0; i < n; i++) {
         check_rw_odp_flow(&flows[i]);
     }
-    return do_ioctl(dpif, ODP_FLOW_QUERY_MULTIPLE, "ODP_FLOW_QUERY_MULTIPLE",
+    return do_ioctl(dpif, ODP_FLOW_GET_MULTIPLE, "ODP_FLOW_GET_MULTIPLE",
                     &fv);
 }
 
@@ -514,8 +535,15 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n,
             flows[i].n_actions = 0;
         }
     }
-    error = do_ioctl(dpif, ODP_FLOW_LIST, "ODP_FLOW_LIST", &fv);
-    *n_out = error ? 0 : fv.n_flows;
+    error = do_ioctl(dpif, ODP_FLOW_LIST, NULL, &fv);
+    if (error) {
+        *n_out = 0;
+        VLOG_WARN_RL(&error_rl, "dp%u: flow list failed (%s)",
+                     dpif->minor, strerror(error));
+    } else {
+        *n_out = fv.n_flows;
+        VLOG_DBG_RL(&dpmsg_rl, "dp%u: listed %zu flows", dpif->minor, *n_out);
+    }
     return error;
 }
 
index 070d28aa4d7c9e246f7154c972683772a0edb77e..3e96e536205e12b9e58a319aab12591e6cf4b35a 100644 (file)
@@ -83,12 +83,10 @@ int dpif_port_group_get(const struct dpif *, uint16_t group,
                         uint16_t ports[], size_t n_ports, size_t *n_out);
 
 int dpif_flow_flush(struct dpif *);
-int dpif_flow_add(struct dpif *, struct odp_flow *);
-int dpif_flow_set_actions(struct dpif *, const struct odp_flow_key *,
-                          const union odp_action *actions, size_t n_actions);
+int dpif_flow_put(struct dpif *, struct odp_flow_put *);
 int dpif_flow_del(struct dpif *, struct odp_flow *);
-int dpif_flow_query(const struct dpif *, struct odp_flow *);
-int dpif_flow_query_multiple(const struct dpif *, struct odp_flow[], size_t n);
+int dpif_flow_get(const struct dpif *, struct odp_flow *);
+int dpif_flow_get_multiple(const struct dpif *, struct odp_flow[], size_t n);
 int dpif_flow_list(const struct dpif *, struct odp_flow[], size_t n,
                    size_t *n_out);
 int dpif_flow_list_all(const struct dpif *,
index 2252c0e946497f22c635de9c004bb5b481f2fe19..c5b443e8b0fd79e5206fb3e22fceb3904e6ded29 100644 (file)
@@ -1548,22 +1548,31 @@ rule_make_actions(struct ofproto *p, struct rule *rule,
     }
 }
 
+static int
+do_put_flow(struct ofproto *ofproto, struct rule *rule, int flags,
+            struct odp_flow_put *put)
+{
+    memset(&put->flow.stats, 0, sizeof put->flow.stats);
+    put->flow.key = rule->cr.flow;
+    put->flow.actions = rule->odp_actions;
+    put->flow.n_actions = rule->n_odp_actions;
+    put->flags = flags;
+    return dpif_flow_put(&ofproto->dpif, put);
+}
+
 static void
-rule_install(struct ofproto *p, struct rule *rule,
-             struct rule *displaced_rule)
+rule_install(struct ofproto *p, struct rule *rule, struct rule *displaced_rule)
 {
     assert(!rule->cr.wc.wildcards);
 
     if (rule->may_install) {
-        struct odp_flow odp_flow;
-
-        odp_flow.key = rule->cr.flow;
-        odp_flow.actions = rule->odp_actions;
-        odp_flow.n_actions = rule->n_odp_actions;
-        if (!dpif_flow_add(&p->dpif, &odp_flow)) {
+        struct odp_flow_put put;
+        if (!do_put_flow(p, rule,
+                         ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS,
+                         &put)) {
             rule->installed = true;
             if (displaced_rule) {
-                update_stats(rule, &odp_flow.stats);
+                update_stats(rule, &put.flow.stats);
                 rule_post_uninstall(p, displaced_rule);
             }
         }
@@ -1581,8 +1590,8 @@ rule_update_actions(struct ofproto *ofproto, struct rule *rule)
             if (actions_changed) {
                 /* XXX should really do rule_post_uninstall() for the *old* set
                  * of actions, and distinguish the old stats from the new. */
-                dpif_flow_set_actions(&ofproto->dpif, &rule->cr.flow,
-                                      rule->odp_actions, rule->n_odp_actions);
+                struct odp_flow_put put;
+                do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY, &put);
             }
         } else {
             rule_install(ofproto, rule, NULL);
@@ -2329,7 +2338,7 @@ query_stats(struct ofproto *p, struct rule *rule,
 
     packet_count = rule->packet_count;
     byte_count = rule->byte_count;
-    if (!dpif_flow_query_multiple(&p->dpif, odp_flows, n_odp_flows)) {
+    if (!dpif_flow_get_multiple(&p->dpif, odp_flows, n_odp_flows)) {
         size_t i;
         for (i = 0; i < n_odp_flows; i++) {
             struct odp_flow *odp_flow = &odp_flows[i];
index 5fa5fa4bbcd6bc808807c974d0e24b0c15bbbbb1..62dba7abac84aafa81c7810e41b3d670e46d75cc 100644 (file)
@@ -557,7 +557,7 @@ do_dp_dump_flows(const struct settings *s UNUSED,
 
         f->actions = actions;
         f->n_actions = MAX_ACTIONS;
-        dpif_flow_query(&dpif, f);
+        dpif_flow_get(&dpif, f);
 
         ds_clear(&ds);
         format_odp_flow(&ds, f);