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)
+ struct ofpbuf **bufp,
+ struct nlattr **maskp, size_t *mask_len,
+ struct nlattr **actionsp, size_t *actions_len,
+ struct dpif_flow_stats *stats)
{
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, key, key_len, &reply, bufp);
if (!error) {
- if (stats) {
- dpif_linux_flow_get_stats(&reply, stats);
+ if (maskp) {
+ *maskp = CONST_CAST(struct nlattr *, reply.mask);
+ *mask_len = reply.mask_len;
}
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);
+ *actionsp = CONST_CAST(struct nlattr *, reply.actions);
+ *actions_len = reply.actions_len;
+ }
+ if (stats) {
+ dpif_linux_flow_get_stats(&reply, stats);
}
}
return error;
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)
+ struct ofpbuf **bufp,
+ struct nlattr **maskp, size_t *mask_len,
+ struct nlattr **actionsp, size_t *actions_len,
+ struct dpif_flow_stats *stats)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *netdev_flow;
get_dpif_flow_stats(netdev_flow, stats);
}
- if (actionsp) {
+ if (maskp || actionsp) {
struct dp_netdev_actions *actions;
+ size_t len = 0;
actions = dp_netdev_flow_get_actions(netdev_flow);
- *actionsp = ofpbuf_clone_data(actions->actions, actions->size);
+ len += maskp ? sizeof(struct odputil_keybuf) : 0;
+ len += actionsp ? actions->size : 0;
+
+ *bufp = ofpbuf_new(len);
+ if (maskp) {
+ struct flow_wildcards wc;
+
+ minimask_expand(&netdev_flow->cr.match.mask, &wc);
+ odp_flow_key_from_mask(*bufp, &wc.masks, &netdev_flow->flow,
+ odp_to_u32(wc.masks.in_port.odp_port),
+ SIZE_MAX);
+ *maskp = ofpbuf_data(*bufp);
+ *mask_len = ofpbuf_size(*bufp);
+ }
+ if (actionsp) {
+ struct dp_netdev_actions *actions;
+
+ actions = dp_netdev_flow_get_actions(netdev_flow);
+ *actionsp = ofpbuf_put(*bufp, actions->actions, actions->size);
+ *actions_len = actions->size;
+ }
}
} else {
error = ENOENT;
* 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.
+ * On success, '*bufp' will be set to an ofpbuf owned by the caller that
+ * contains the response for 'maskp' and 'actionsp'. The caller must supply
+ * a valid pointer, and must free the ofpbuf (with ofpbuf_delete()) when it
+ * is no longer needed.
+ *
+ * If 'maskp' is nonnull, then on success '*maskp' will point to the
+ * Netlink attributes for the flow's mask, stored in '*bufp'. '*mask_len'
+ * will be set to the length of the mask attributes.
+ *
+ * If 'actionsp' is nonnull, then on success '*actionsp' will point to the
+ * Netlink attributes for the flow's actions, stored in '*bufp'.
+ * '*actions_len' will be set to the length of the actions attributes.
*
* If '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);
+ struct ofpbuf **bufp,
+ struct nlattr **maskp, size_t *mask_len,
+ struct nlattr **actionsp, size_t *acts_len,
+ struct dpif_flow_stats *stats);
/* 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
* 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' 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
- * it is no longer needed.
+ * On success, '*bufp' will be set to an ofpbuf owned by the caller that
+ * contains the response for 'maskp' and 'actionsp'. The caller must supply
+ * a valid pointer, and must free the ofpbuf (with ofpbuf_delete()) when it
+ * is no longer needed.
+ *
+ * If 'maskp' is nonnull, then on success '*maskp' will point to the
+ * Netlink attributes for the flow's mask, stored in '*bufp'. '*mask_len'
+ * will be set to the length of the mask attributes.
+ *
+ * If 'actionsp' is nonnull, then on success '*actionsp' will point to the
+ * Netlink attributes for the flow's actions, stored in '*bufp'.
+ * '*actions_len' will be set to the length of the actions attributes.
*
* If 'stats' is nonnull, then on success it will be updated with the flow's
* statistics. */
int
dpif_flow_get(const struct dpif *dpif,
- const struct nlattr *key, size_t key_len,
- struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
+ const struct nlattr *key, size_t key_len, struct ofpbuf **bufp,
+ struct nlattr **maskp, size_t *mask_len,
+ struct nlattr **actionsp, size_t *actions_len,
+ struct dpif_flow_stats *stats)
{
int error;
COVERAGE_INC(dpif_flow_get);
- error = dpif->dpif_class->flow_get(dpif, key, key_len, actionsp, stats);
+ *bufp = NULL;
+ error = dpif->dpif_class->flow_get(dpif, key, key_len, bufp,
+ maskp, mask_len,
+ actionsp, actions_len,
+ stats);
if (error) {
if (actionsp) {
*actionsp = NULL;
+ *actions_len = 0;
+ }
+ if (maskp) {
+ *maskp = NULL;
+ *mask_len = 0;
}
if (stats) {
memset(stats, 0, sizeof *stats);
}
+ ofpbuf_delete(*bufp);
}
if (should_log_flow_message(error)) {
const struct nlattr *actions;
- size_t actions_len;
+ size_t acts_len;
if (!error && actionsp) {
- actions = ofpbuf_data(*actionsp);
- actions_len = ofpbuf_size(*actionsp);
+ actions = *actionsp;
+ acts_len = *actions_len;
} else {
actions = NULL;
- actions_len = 0;
+ acts_len = 0;
}
log_flow_message(dpif, error, "flow_get", key, key_len,
- NULL, 0, stats, actions, actions_len);
+ NULL, 0, stats, actions, acts_len);
}
return error;
}
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 *);
+ struct ofpbuf **bufp,
+ struct nlattr **maskp, size_t *mask_len,
+ struct nlattr **actionsp, size_t *acts_len,
+ struct dpif_flow_stats *stats);
struct dpif_flow_dump {
const struct dpif *dpif;