This patch adds support for batching flow_get operations to the dpif. As part of this, it also now allows fetching the mask (this was previously not possible using a 'get' operation).
Signed-off-by: Joe Stringer <joestrin...@nicira.com> --- lib/dpif-linux.c | 70 +++++++++++++++++++++++++++++++------------- lib/dpif-netdev.c | 41 ++++++++++++++++---------- lib/dpif-provider.h | 19 ++++++------ lib/dpif.c | 80 +++++++++++++++++++++++++++++++++------------------ lib/dpif.h | 17 +++++++++-- 5 files changed, 154 insertions(+), 73 deletions(-) diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 0eac3e7..2cf6de1 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -126,6 +126,8 @@ static int dpif_linux_flow_transact(struct dpif_linux_flow *request, struct ofpbuf **bufp); static void dpif_linux_flow_get_stats(const struct dpif_linux_flow *, struct dpif_flow_stats *); +static void dpif_linux_flow_to_dpif_flow(struct dpif_flow *, + const struct dpif_linux_flow *); /* One of the dpif channels between the kernel and userspace. */ struct dpif_channel { @@ -1029,6 +1031,18 @@ dpif_linux_port_poll_wait(const struct dpif *dpif_) } } +static void +dpif_linux_init_flow_get(const struct dpif_linux *dpif, + const struct nlattr *key, size_t key_len, + struct dpif_linux_flow *request) +{ + dpif_linux_flow_init(request); + request->cmd = OVS_FLOW_CMD_GET; + request->dp_ifindex = dpif->dp_ifindex; + request->key = key; + request->key_len = key_len; +} + static int dpif_linux_flow_get__(const struct dpif_linux *dpif, const struct nlattr *key, size_t key_len, @@ -1036,36 +1050,22 @@ dpif_linux_flow_get__(const struct dpif_linux *dpif, { struct dpif_linux_flow request; - dpif_linux_flow_init(&request); - request.cmd = OVS_FLOW_CMD_GET; - request.dp_ifindex = dpif->dp_ifindex; - request.key = key; - request.key_len = key_len; + dpif_linux_init_flow_get(dpif, key, key_len, &request); return dpif_linux_flow_transact(&request, reply, bufp); } static int -dpif_linux_flow_get(const struct dpif *dpif_, - const struct nlattr *key, size_t key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *stats) +dpif_linux_flow_get(const struct dpif *dpif_, const struct dpif_flow_get *get) { const struct dpif_linux *dpif = dpif_linux_cast(dpif_); struct dpif_linux_flow reply; struct ofpbuf *buf; int error; - error = dpif_linux_flow_get__(dpif, key, key_len, &reply, &buf); + error = dpif_linux_flow_get__(dpif, get->key, get->key_len, &reply, &buf); if (!error) { - if (stats) { - dpif_linux_flow_get_stats(&reply, stats); - } - if (actionsp) { - ofpbuf_set_data(buf, CONST_CAST(struct nlattr *, reply.actions)); - ofpbuf_set_size(buf, reply.actions_len); - *actionsp = buf; - } else { - ofpbuf_delete(buf); - } + *get->buffer = *buf; + dpif_linux_flow_to_dpif_flow(get->flow, &reply); } return error; } @@ -1235,7 +1235,7 @@ dpif_linux_flow_dump_thread_destroy(struct dpif_flow_dump_thread *thread_) static void dpif_linux_flow_to_dpif_flow(struct dpif_flow *dpif_flow, - struct dpif_linux_flow *linux_flow) + const struct dpif_linux_flow *linux_flow) { dpif_flow->key = linux_flow->key; dpif_flow->key_len = linux_flow->key_len; @@ -1385,6 +1385,7 @@ dpif_linux_operate__(struct dpif_linux *dpif, struct dpif_flow_put *put; struct dpif_flow_del *del; struct dpif_execute *execute; + struct dpif_flow_get *get; struct dpif_linux_flow flow; ofpbuf_use_stub(&aux->request, @@ -1421,6 +1422,14 @@ dpif_linux_operate__(struct dpif_linux *dpif, &aux->request); break; + case DPIF_OP_FLOW_GET: + get = &op->u.flow_get; + dpif_linux_init_flow_get(dpif, get->key, get->key_len, &flow); + flow.nlmsg_flags |= NLM_F_ECHO; + aux->txn.reply = &aux->reply; + dpif_linux_flow_to_ofpbuf(&flow, &aux->request); + break; + default: OVS_NOT_REACHED(); } @@ -1437,6 +1446,7 @@ dpif_linux_operate__(struct dpif_linux *dpif, struct dpif_op *op = ops[i]; struct dpif_flow_put *put; struct dpif_flow_del *del; + struct dpif_flow_get *get; op->error = txn->error; @@ -1482,6 +1492,26 @@ dpif_linux_operate__(struct dpif_linux *dpif, case DPIF_OP_EXECUTE: break; + case DPIF_OP_FLOW_GET: + get = &op->u.flow_get; + if (!op->error) { + struct dpif_linux_flow reply; + + op->error = dpif_linux_flow_from_ofpbuf(&reply, + txn->reply); + if (!op->error) { + /* Steal the reply */ + *get->buffer = *txn->reply; + txn->reply = NULL; + dpif_linux_flow_to_dpif_flow(get->flow, &reply); + } + } + + if (op->error) { + memset(get->flow, 0, sizeof *get->flow); + } + break; + default: OVS_NOT_REACHED(); } diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 58c629b..c3fde36 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1101,7 +1101,7 @@ dp_netdev_find_flow(const struct dp_netdev *dp, const struct flow *flow) } static void -get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow, +get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow, struct dpif_flow_stats *stats) { struct dp_netdev_flow_stats *bucket; @@ -1118,6 +1118,28 @@ get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow, } } +static void +dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow *netdev_flow, + struct ofpbuf *buf, struct dpif_flow *flow) +{ + struct flow_wildcards wc; + struct dp_netdev_actions *actions; + + minimask_expand(&netdev_flow->cr.match.mask, &wc); + ofpbuf_init(buf, sizeof(struct odputil_keybuf)); + odp_flow_key_from_mask(buf, &wc.masks, &netdev_flow->flow, + odp_to_u32(wc.masks.in_port.odp_port), + SIZE_MAX, true); + flow->mask = ofpbuf_data(buf); + flow->mask_len = ofpbuf_size(buf); + + actions = dp_netdev_flow_get_actions(netdev_flow); + flow->actions = ofpbuf_put(buf, actions->actions, actions->size); + flow->actions_len = actions->size; + + get_dpif_flow_stats(netdev_flow, &flow->stats); +} + static int dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, const struct nlattr *mask_key, @@ -1211,16 +1233,14 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, } static int -dpif_netdev_flow_get(const struct dpif *dpif, - const struct nlattr *nl_key, size_t nl_key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *stats) +dpif_netdev_flow_get(const struct dpif *dpif, const struct dpif_flow_get *get) { struct dp_netdev *dp = get_dp_netdev(dpif); struct dp_netdev_flow *netdev_flow; struct flow key; int error; - error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key); + error = dpif_netdev_flow_from_nlattrs(get->key, get->key_len, &key); if (error) { return error; } @@ -1230,16 +1250,7 @@ dpif_netdev_flow_get(const struct dpif *dpif, fat_rwlock_unlock(&dp->cls.rwlock); if (netdev_flow) { - if (stats) { - get_dpif_flow_stats(netdev_flow, stats); - } - - if (actionsp) { - struct dp_netdev_actions *actions; - - actions = dp_netdev_flow_get_actions(netdev_flow); - *actionsp = ofpbuf_clone_data(actions->actions, actions->size); - } + dp_netdev_flow_to_dpif_flow(netdev_flow, get->buffer, get->flow); } else { error = ENOENT; } diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index b762ac0..13e426c 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -246,16 +246,19 @@ struct dpif_class { * Returns 0 if successful. If no flow matches, returns ENOENT. On other * failure, returns a positive errno value. * - * If 'actionsp' is nonnull, then on success '*actionsp' must be set to an - * ofpbuf owned by the caller that contains the Netlink attributes for the - * flow's actions. The caller must free the ofpbuf (with ofpbuf_delete()) - * when it is no longer needed. + * If 'get->mask' is nonnull, then on success '*get->mask' must be set to + * an ofpbuf owned by the caller that contains the Netlink attributes for + * the flow's actions. The caller must free the ofpbuf (with + * ofpbuf_delete()) when it is no longer needed. * - * If 'stats' is nonnull, then on success it must be updated with the + * If 'get->actions' is nonnull, then on success '*get->actions' must be + * set to an ofpbuf owned by the caller that contains the Netlink + * attributes for the flow's actions. The caller must free the ofpbuf + * (with ofpbuf_delete()) when it is no longer needed. + * + * If 'get->stats' is nonnull, then on success it must be updated with the * flow's statistics. */ - int (*flow_get)(const struct dpif *dpif, - const struct nlattr *key, size_t key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *stats); + int (*flow_get)(const struct dpif *dpif, const struct dpif_flow_get *get); /* Adds or modifies a flow in 'dpif'. The flow is specified by the Netlink * attributes with types OVS_KEY_ATTR_* in the 'put->key_len' bytes diff --git a/lib/dpif.c b/lib/dpif.c index 2b6f36d..e7744f4 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -97,6 +97,8 @@ static void log_flow_del_message(struct dpif *, const struct dpif_flow_del *, int error); static void log_execute_message(struct dpif *, const struct dpif_execute *, bool subexecute, int error); +static void log_flow_get_message(const struct dpif *, + const struct dpif_flow_get *, int error); static void dp_initialize(void) @@ -827,6 +829,22 @@ dpif_flow_flush(struct dpif *dpif) return error; } +static int +dpif_flow_get__(const struct dpif *dpif, const struct dpif_flow_get *get) +{ + int error; + + COVERAGE_INC(dpif_flow_get); + + error = dpif->dpif_class->flow_get(dpif, get); + if (error) { + memset(get->flow, 0, sizeof *get->flow); + } + log_flow_get_message(dpif, get, error); + + return error; +} + /* Queries 'dpif' for a flow entry. The flow is specified by the Netlink * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at * 'key'. @@ -834,6 +852,11 @@ dpif_flow_flush(struct dpif *dpif) * Returns 0 if successful. If no flow matches, returns ENOENT. On other * failure, returns a positive errno value. * + * If 'maskp' is nonnull, then on success '*maskp' will be set to an ofpbuf + * owned by the caller that contains the Netlink attributes for the flow's + * mask. The caller must free the ofpbuf (with ofpbuf_delete()) when it is no + * longer needed. + * * If 'actionsp' is nonnull, then on success '*actionsp' will be set to an * ofpbuf owned by the caller that contains the Netlink attributes for the * flow's actions. The caller must free the ofpbuf (with ofpbuf_delete()) when @@ -844,36 +867,17 @@ dpif_flow_flush(struct dpif *dpif) int dpif_flow_get(const struct dpif *dpif, const struct nlattr *key, size_t key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *stats) + struct ofpbuf *buffer, struct dpif_flow *flow) { - int error; - - COVERAGE_INC(dpif_flow_get); - - error = dpif->dpif_class->flow_get(dpif, key, key_len, actionsp, stats); - if (error) { - if (actionsp) { - *actionsp = NULL; - } - if (stats) { - memset(stats, 0, sizeof *stats); - } - } - if (should_log_flow_message(error)) { - const struct nlattr *actions; - size_t actions_len; + struct dpif_flow_get get; - if (!error && actionsp) { - actions = ofpbuf_data(*actionsp); - actions_len = ofpbuf_size(*actionsp); - } else { - actions = NULL; - actions_len = 0; - } - log_flow_message(dpif, error, "flow_get", key, key_len, - NULL, 0, stats, actions, actions_len); - } - return error; + get.key = key; + get.key_len = key_len; + get.buffer = buffer; + get.flow = flow; + get.flow->key = key; + get.flow->key_len = key_len; + return dpif_flow_get__(dpif, &get); } static int @@ -1237,6 +1241,9 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops) log_execute_message(dpif, &op->u.execute, false, op->error); break; + case DPIF_OP_FLOW_GET: + log_flow_get_message(dpif, &op->u.flow_get, op->error); + break; } } @@ -1270,6 +1277,10 @@ dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops) op->error = dpif_execute(dpif, &op->u.execute); break; + case DPIF_OP_FLOW_GET: + op->error = dpif_flow_get__(dpif, &op->u.flow_get); + break; + default: OVS_NOT_REACHED(); } @@ -1596,3 +1607,16 @@ log_execute_message(struct dpif *dpif, const struct dpif_execute *execute, free(packet); } } + +static void +log_flow_get_message(const struct dpif *dpif, const struct dpif_flow_get *get, + int error) +{ + if (should_log_flow_message(error)) { + log_flow_message(dpif, error, "flow_get", + get->key, get->key_len, + get->flow->mask, get->flow->mask_len, + &get->flow->stats, + get->flow->actions, get->flow->actions_len); + } +} diff --git a/lib/dpif.h b/lib/dpif.h index f080cde..57ad5a2 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -405,6 +405,7 @@ struct flow; struct nlattr; struct sset; struct dpif_class; +struct dpif_flow; int dp_register_provider(const struct dpif_class *); int dp_unregister_provider(const char *type); @@ -523,8 +524,8 @@ int dpif_flow_del(struct dpif *, const struct nlattr *key, size_t key_len, struct dpif_flow_stats *); int dpif_flow_get(const struct dpif *, - const struct nlattr *key, size_t key_len, - struct ofpbuf **actionsp, struct dpif_flow_stats *); + const struct nlattr *key, size_t key_len, struct ofpbuf *, + struct dpif_flow *); /* Flow dumping interface * ====================== @@ -584,6 +585,7 @@ enum dpif_op_type { DPIF_OP_FLOW_PUT = 1, DPIF_OP_FLOW_DEL, DPIF_OP_EXECUTE, + DPIF_OP_FLOW_GET, }; struct dpif_flow_put { @@ -626,6 +628,16 @@ struct dpif_execute { bool needs_help; }; +struct dpif_flow_get { + /* Input. */ + const struct nlattr *key; /* Flow to get. */ + size_t key_len; /* Length of 'key' in bytes. */ + struct ofpbuf *buffer; /* Storage for output parameters. */ + + /* Output. */ + struct dpif_flow *flow; /* Resulting flow from datapath. */ +}; + int dpif_execute(struct dpif *, struct dpif_execute *); struct dpif_op { @@ -635,6 +647,7 @@ struct dpif_op { struct dpif_flow_put flow_put; struct dpif_flow_del flow_del; struct dpif_execute execute; + struct dpif_flow_get flow_get; } u; }; -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev