+{
+ struct ds s;
+
+ ds_init(&s);
+ ds_put_cstr(&s, op);
+ ds_put_cstr(&s, " (");
+ odp_format_ufid(ufid, &s);
+ ds_put_cstr(&s, ")");
+ if (key_len) {
+ ds_put_cstr(&s, "\nflow (verbose): ");
+ odp_flow_format(key, key_len, mask, mask_len, NULL, &s, true);
+ ds_put_cstr(&s, "\nflow: ");
+ odp_flow_format(key, key_len, mask, mask_len, NULL, &s, false);
+ }
+ ds_put_cstr(&s, "\nactions: ");
+ format_odp_actions(&s, actions, actions_len);
+ VLOG_DBG("\n%s", ds_cstr(&s));
+ ds_destroy(&s);
+}
+
+static int
+try_send_to_netdev(struct dpif_netlink *dpif, struct dpif_op *op)
{
- struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
+ switch (op->type) {
+ case DPIF_OP_FLOW_PUT: {
+ struct dpif_flow_put *put = &op->u.flow_put;
+ if (!put->ufid) {
+ break;
+ }
+ dbg_print_flow(put->key, put->key_len, put->mask, put->mask_len,
+ put->actions, put->actions_len, put->ufid,
+ (put->flags & DPIF_FP_MODIFY ? "PUT(MODIFY)" : "PUT"));
+ return parse_flow_put(dpif, put);
+ }
+ case DPIF_OP_FLOW_DEL:
+ case DPIF_OP_FLOW_GET:
+ case DPIF_OP_EXECUTE:
+ default:
+ break;
+ }
+ return EOPNOTSUPP;
+}
+
+static void
+dpif_netlink_operate_chunks(struct dpif_netlink *dpif, struct dpif_op **ops,
+ size_t n_ops)
+{
while (n_ops > 0) {
size_t chunk = dpif_netlink_operate__(dpif, ops, n_ops);
+
ops += chunk;
n_ops -= chunk;
}
}
+static void
+dpif_netlink_operate(struct dpif *dpif_, struct dpif_op **ops, size_t n_ops)
+{
+ struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
+ struct dpif_op *new_ops[OPERATE_MAX_OPS];
+ int count = 0;
+ int i = 0;
+ int err = 0;
+
+ if (netdev_flow_api_enabled) {
+ while (n_ops > 0) {
+ count = 0;
+
+ while (n_ops > 0 && count < OPERATE_MAX_OPS) {
+ struct dpif_op *op = ops[i++];
+
+ err = try_send_to_netdev(dpif, op);
+ if (err && err != EEXIST) {
+ new_ops[count++] = op;
+ } else {
+ op->error = err;
+ }
+
+ n_ops--;
+ }
+
+ dpif_netlink_operate_chunks(dpif, new_ops, count);
+ }
+
+ return;
+ }
+
+ dpif_netlink_operate_chunks(dpif, ops, n_ops);
+}
+
#if _WIN32
static void
dpif_netlink_handler_uninit(struct dpif_handler *handler)
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 8747778..349425e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -41,6 +41,7 @@
#include "util.h"
#include "uuid.h"
#include "openvswitch/vlog.h"
+#include "openvswitch/match.h"
VLOG_DEFINE_THIS_MODULE(odp_util);
@@ -5497,6 +5498,58 @@ odp_flow_key_to_mask(const struct nlattr *mask_key,
size_t mask_key_len,
}
}
+/* Converts the netlink formated key/mask to match.
+ * Fails if odp_flow_key_from_key/mask and odp_flow_key_key/mask
+ * disagree on the acceptable form of flow */
+int
+parse_key_and_mask_to_match(const struct nlattr *key, size_t key_len,
+ const struct nlattr *mask, size_t mask_len,
+ struct match *match)
+{
+ enum odp_key_fitness fitness;
+
+ fitness = odp_flow_key_to_flow(key, key_len, &match->flow);
+ if (fitness) {
+ /* This should not happen: it indicates that odp_flow_key_from_flow()
+ * and odp_flow_key_to_flow() disagree on the acceptable form of a
+ * flow. Log the problem as an error, with enough details to enable
+ * debugging. */
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ if (!VLOG_DROP_ERR(&rl)) {
+ struct ds s;
+
+ ds_init(&s);
+ odp_flow_format(key, key_len, NULL, 0, NULL, &s, true);
+ VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
+ return EINVAL;
+ }
+
+ fitness = odp_flow_key_to_mask(mask, mask_len, &match->wc, &match->flow);
+ if (fitness) {
+ /* This should not happen: it indicates that
+ * odp_flow_key_from_mask() and odp_flow_key_to_mask()
+ * disagree on the acceptable form of a mask. Log the problem
+ * as an error, with enough details to enable debugging. */
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ if (!VLOG_DROP_ERR(&rl)) {
+ struct ds s;
+
+ VLOG_ERR("internal error parsing flow mask %s (%s)",
+ ds_cstr(&s), odp_key_fitness_to_string(fitness));
+ ds_destroy(&s);