From 29a1100c365ebfa4c66d51063fe5bcf83dd048ec Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 4 May 2009 16:10:28 -0700 Subject: [PATCH] datapath: Generalize flow creation and modification. 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 | 212 +++++++++++++++------------ datapath/datapath.h | 3 +- datapath/flow.c | 28 +--- datapath/flow.h | 3 +- datapath/table.c | 10 +- include/openflow/datapath-protocol.h | 31 ++-- lib/dpif.c | 84 +++++++---- lib/dpif.h | 8 +- secchan/ofproto.c | 33 +++-- utilities/dpctl.c | 2 +- 10 files changed, 232 insertions(+), 182 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 899ed495..03afe3a7 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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; diff --git a/datapath/datapath.h b/datapath/datapath.h index bb9ce0a3..71831ebd 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -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 *); diff --git a/datapath/flow.c b/datapath/flow.c index 024b61cd..c9a6e9d0 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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) { diff --git a/datapath/flow.h b/datapath/flow.h index f44774fe..5d3fd260 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -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 *); diff --git a/datapath/table.c b/datapath/table.c index 7890442d..88aa7d2a 100644 --- a/datapath/table.c +++ b/datapath/table.c @@ -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]; diff --git a/include/openflow/datapath-protocol.h b/include/openflow/datapath-protocol.h index c65293cd..cf5075ec 100644 --- a/include/openflow/datapath-protocol.h +++ b/include/openflow/datapath-protocol.h @@ -63,18 +63,18 @@ #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; diff --git a/lib/dpif.c b/lib/dpif.c index 119b40c3..0ff68a5a 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -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; } diff --git a/lib/dpif.h b/lib/dpif.h index 070d28aa..3e96e536 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -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 *, diff --git a/secchan/ofproto.c b/secchan/ofproto.c index 2252c0e9..c5b443e8 100644 --- a/secchan/ofproto.c +++ b/secchan/ofproto.c @@ -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]; diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 5fa5fa4b..62dba7ab 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -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); -- 2.30.2