Signed-off-by: Eelco Chaudron <[email protected]>
---
v2 changes:
- Fix indentation in dpif_offload_dummy_cleanup_flow_pmd_data().
- Renamed remote_from_port to remove_from_port variable.
---
lib/dpif-offload-dummy.c | 610 +++++++++++++++++++++++++++++++++++++--
lib/dummy.h | 6 +
lib/netdev-dummy.c | 4 +-
tests/dpif-netdev.at | 33 +--
4 files changed, 608 insertions(+), 45 deletions(-)
diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c
index ce849e3dd..cd2474df8 100644
--- a/lib/dpif-offload-dummy.c
+++ b/lib/dpif-offload-dummy.c
@@ -21,25 +21,262 @@
#include "dpif-offload-provider.h"
#include "dpif-offload.h"
#include "dummy.h"
+#include "id-fpool.h"
#include "netdev-provider.h"
+#include "odp-util.h"
#include "util.h"
+#include "uuid.h"
#include "openvswitch/json.h"
+#include "openvswitch/match.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(dpif_offload_dummy);
+
+struct pmd_id_data {
+ struct hmap_node node;
+ void *flow_reference;
+ unsigned pmd_id;
+};
+
+struct dummy_offloaded_flow {
+ struct hmap_node node;
+ struct match match;
+ ovs_u128 ufid;
+ uint32_t mark;
+
+ /* The pmd_id_map below is also protected by the port_mutex. */
+ struct hmap pmd_id_map;
+ };
struct dpif_offload_dummy {
struct dpif_offload offload;
struct dpif_offload_port_mgr *port_mgr;
+ struct id_fpool *flow_mark_pool;
+ dpif_offload_flow_unreference_cb *unreference_cb;
/* Configuration specific variables. */
struct ovsthread_once once_enable; /* Track first-time enablement. */
};
+struct dpif_offload_dummy_port {
+ struct dpif_offload_port_mgr_port pm_port;
+
+ struct ovs_mutex port_mutex; /* Protect all below members. */
+ struct hmap offloaded_flows OVS_GUARDED;
+};
+
+static void dpif_offload_dummy_flow_unreference(struct dpif_offload_dummy *,
+ unsigned pmd_id,
+ void *flow_reference);
+
+static uint32_t
+dpif_offload_dummy_allocate_flow_mark(struct dpif_offload_dummy *offload_dummy)
+{
+ static struct ovsthread_once init_once = OVSTHREAD_ONCE_INITIALIZER;
+ uint32_t flow_mark;
+
+ if (ovsthread_once_start(&init_once)) {
+ /* Haven't initiated yet, do it here. */
+ offload_dummy->flow_mark_pool = id_fpool_create(1, 1, UINT32_MAX - 1);
+ ovsthread_once_done(&init_once);
+ }
+
+ if (id_fpool_new_id(offload_dummy->flow_mark_pool, 0, &flow_mark)) {
+ return flow_mark;
+ }
+
+ return INVALID_FLOW_MARK;
+}
+
+static void
+dpif_offload_dummy_free_flow_mark(struct dpif_offload_dummy *offload_dummy,
+ uint32_t flow_mark)
+{
+ if (flow_mark != INVALID_FLOW_MARK) {
+ id_fpool_free_id(offload_dummy->flow_mark_pool, 0, flow_mark);
+ }
+}
+
+static struct dpif_offload_dummy_port *
+dpif_offload_dummy_cast_port(struct dpif_offload_port_mgr_port *port)
+{
+ return CONTAINER_OF(port, struct dpif_offload_dummy_port, pm_port);
+}
+
static struct dpif_offload_dummy *
dpif_offload_dummy_cast(const struct dpif_offload *offload)
{
return CONTAINER_OF(offload, struct dpif_offload_dummy, offload);
}
+static uint32_t
+dpif_offload_dummy_flow_hash(const ovs_u128 *ufid)
+{
+ return ufid->u32[0];
+}
+
+static struct pmd_id_data *
+dpif_offload_dummy_find_flow_pmd_data(
+ struct dpif_offload_dummy_port *port OVS_UNUSED,
+ struct dummy_offloaded_flow *off_flow, unsigned pmd_id)
+ OVS_REQUIRES(port->port_mutex)
+{
+ size_t hash = hash_int(pmd_id, 0);
+ struct pmd_id_data *data;
+
+ HMAP_FOR_EACH_WITH_HASH (data, node, hash, &off_flow->pmd_id_map) {
+ if (data->pmd_id == pmd_id) {
+ return data;
+ }
+ }
+ return NULL;
+}
+
+static void
+dpif_offload_dummy_add_flow_pmd_data(
+ struct dpif_offload_dummy_port *port OVS_UNUSED,
+ struct dummy_offloaded_flow *off_flow, unsigned pmd_id,
+ void *flow_reference) OVS_REQUIRES(port->port_mutex)
+{
+ struct pmd_id_data *pmd_data = xmalloc(sizeof *pmd_data);
+
+ pmd_data->pmd_id = pmd_id;
+ pmd_data->flow_reference = flow_reference;
+ hmap_insert(&off_flow->pmd_id_map, &pmd_data->node,
+ hash_int(pmd_id, 0));
+}
+
+static void
+dpif_offload_dummy_update_add_flow_pmd_data(
+ struct dpif_offload_dummy_port *port,
+ struct dummy_offloaded_flow *off_flow, unsigned pmd_id,
+ void *flow_reference, void **previous_flow_reference)
+ OVS_REQUIRES(port->port_mutex)
+{
+ struct pmd_id_data *data = dpif_offload_dummy_find_flow_pmd_data(port,
+ off_flow,
+ pmd_id);
+
+ if (data) {
+ *previous_flow_reference = data->flow_reference;
+ data->flow_reference = flow_reference;
+ } else {
+ dpif_offload_dummy_add_flow_pmd_data(port, off_flow, pmd_id,
+ flow_reference);
+ *previous_flow_reference = NULL;
+ }
+}
+
+static bool
+dpif_offload_dummy_del_flow_pmd_data(
+ struct dpif_offload_dummy_port *port OVS_UNUSED,
+ struct dummy_offloaded_flow *off_flow, unsigned pmd_id,
+ void *flow_reference) OVS_REQUIRES(port->port_mutex)
+{
+ size_t hash = hash_int(pmd_id, 0);
+ struct pmd_id_data *data;
+
+ HMAP_FOR_EACH_WITH_HASH (data, node, hash, &off_flow->pmd_id_map) {
+ if (data->pmd_id == pmd_id && data->flow_reference == flow_reference) {
+ hmap_remove(&off_flow->pmd_id_map, &data->node);
+ free(data);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void
+dpif_offload_dummy_cleanup_flow_pmd_data(
+ struct dpif_offload_dummy *offload,
+ struct dpif_offload_dummy_port *port OVS_UNUSED,
+ struct dummy_offloaded_flow *off_flow) OVS_REQUIRES(port->port_mutex)
+{
+ struct pmd_id_data *data;
+
+ HMAP_FOR_EACH_SAFE (data, node, &off_flow->pmd_id_map) {
+ hmap_remove(&off_flow->pmd_id_map, &data->node);
+
+ dpif_offload_dummy_flow_unreference(offload, data->pmd_id,
+ data->flow_reference);
+ free(data);
+ }
+}
+
+static struct dummy_offloaded_flow *
+dpif_offload_dummy_add_flow(struct dpif_offload_dummy_port *port,
+ const ovs_u128 *ufid, unsigned pmd_id,
+ void *flow_reference, uint32_t mark)
+ OVS_REQUIRES(port->port_mutex)
+{
+ struct dummy_offloaded_flow *off_flow = xzalloc(sizeof *off_flow);
+
+ off_flow->mark = mark;
+ memcpy(&off_flow->ufid, ufid, sizeof off_flow->ufid);
+ hmap_init(&off_flow->pmd_id_map);
+ dpif_offload_dummy_add_flow_pmd_data(port, off_flow, pmd_id,
+ flow_reference);
+
+ hmap_insert(&port->offloaded_flows, &off_flow->node,
+ dpif_offload_dummy_flow_hash(ufid));
+
+ return off_flow;
+}
+
+static void
+dpif_offload_dummy_free_flow(struct dpif_offload_dummy_port *port,
+ struct dummy_offloaded_flow *off_flow,
+ bool remove_from_port)
+ OVS_REQUIRES(port->port_mutex)
+{
+ if (remove_from_port) {
+ hmap_remove(&port->offloaded_flows, &off_flow->node);
+ }
+ ovs_assert(!hmap_count(&off_flow->pmd_id_map));
+
+ hmap_destroy(&off_flow->pmd_id_map);
+ free(off_flow);
+}
+
+static struct dummy_offloaded_flow *
+dpif_offload_dummy_find_offloaded_flow(struct dpif_offload_dummy_port *port,
+ const ovs_u128 *ufid)
+ OVS_REQUIRES(port->port_mutex)
+{
+ uint32_t hash = dpif_offload_dummy_flow_hash(ufid);
+ struct dummy_offloaded_flow *data;
+
+ HMAP_FOR_EACH_WITH_HASH (data, node, hash, &port->offloaded_flows) {
+ if (ovs_u128_equals(*ufid, data->ufid)) {
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+static struct dummy_offloaded_flow *
+dpif_offload_dummy_find_offloaded_flow_and_update(
+ struct dpif_offload_dummy_port *port, const ovs_u128 *ufid,
+ unsigned pmd_id, void *new_flow_reference, void **previous_flow_reference)
+ OVS_REQUIRES(port->port_mutex)
+{
+ struct dummy_offloaded_flow *off_flow;
+
+ off_flow = dpif_offload_dummy_find_offloaded_flow(port, ufid);
+ if (!off_flow) {
+ return NULL;
+ }
+
+ dpif_offload_dummy_update_add_flow_pmd_data(port, off_flow, pmd_id,
+ new_flow_reference,
+ previous_flow_reference);
+
+ return off_flow;
+}
+
static void
dpif_offload_dummy_enable_offload(struct dpif_offload *dpif_offload,
struct dpif_offload_port_mgr_port *port)
@@ -55,24 +292,69 @@ dpif_offload_dummy_cleanup_offload(
dpif_offload_set_netdev_offload(port->netdev, NULL);
}
+static void
+dpif_offload_dummy_free_port_(struct dpif_offload_dummy *offload,
+ struct dpif_offload_dummy_port *port)
+{
+ struct dummy_offloaded_flow *off_flow;
+
+ ovs_mutex_lock(&port->port_mutex);
+ HMAP_FOR_EACH_POP (off_flow, node, &port->offloaded_flows) {
+ dpif_offload_dummy_cleanup_flow_pmd_data(offload, port, off_flow);
+ dpif_offload_dummy_free_flow(port, off_flow, false);
+ }
+ hmap_destroy(&port->offloaded_flows);
+ ovs_mutex_unlock(&port->port_mutex);
+ ovs_mutex_destroy(&port->port_mutex);
+ free(port);
+}
+
+struct free_port_rcu {
+ struct dpif_offload_dummy *offload;
+ struct dpif_offload_dummy_port *port;
+};
+
+static void
+dpif_offload_dummy_free_port_rcu(struct free_port_rcu *fpc)
+{
+ dpif_offload_dummy_free_port_(fpc->offload, fpc->port);
+ free(fpc);
+}
+
+static void
+dpif_offload_dummy_free_port(struct dpif_offload_dummy *offload,
+ struct dpif_offload_dummy_port *port)
+{
+ struct free_port_rcu *fpc = xmalloc(sizeof *fpc);
+
+ fpc->offload = offload;
+ fpc->port = port;
+ ovsrcu_postpone(dpif_offload_dummy_free_port_rcu, fpc);
+}
+
static int
dpif_offload_dummy_port_add(struct dpif_offload *dpif_offload,
struct netdev *netdev, odp_port_t port_no)
{
- struct dpif_offload_port_mgr_port *port = xmalloc(sizeof *port);
+ struct dpif_offload_dummy_port *port = xmalloc(sizeof *port);
struct dpif_offload_dummy *offload_dummy;
+ ovs_mutex_init(&port->port_mutex);
+ ovs_mutex_lock(&port->port_mutex);
+ hmap_init(&port->offloaded_flows);
+ ovs_mutex_unlock(&port->port_mutex);
+
offload_dummy = dpif_offload_dummy_cast(dpif_offload);
- if (dpif_offload_port_mgr_add(offload_dummy->port_mgr, port, netdev,
- port_no, false)) {
+ if (dpif_offload_port_mgr_add(offload_dummy->port_mgr, &port->pm_port,
+ netdev, port_no, false)) {
if (dpif_offload_is_offload_enabled()) {
- dpif_offload_dummy_enable_offload(dpif_offload, port);
+ dpif_offload_dummy_enable_offload(dpif_offload, &port->pm_port);
}
return 0;
}
- free(port);
+ dpif_offload_dummy_free_port_(offload_dummy, port);
return EEXIST;
}
@@ -88,11 +370,15 @@ dpif_offload_dummy_port_del(struct dpif_offload *dpif_offload,
port = dpif_offload_port_mgr_remove(offload_dummy->port_mgr, port_no,
true);
if (port) {
+ struct dpif_offload_dummy_port *dummy_port;
+
+ dummy_port = dpif_offload_dummy_cast_port(port);
if (dpif_offload_is_offload_enabled()) {
dpif_offload_dummy_cleanup_offload(dpif_offload, port);
}
netdev_close(port->netdev);
- ovsrcu_postpone(free, port);
+
+ dpif_offload_dummy_free_port(offload_dummy, dummy_port);
}
return 0;
}
@@ -156,6 +442,8 @@ dpif_offload_dummy_open(const struct dpif_offload_class
*offload_class,
offload_dummy->port_mgr = dpif_offload_port_mgr_init();
offload_dummy->once_enable = (struct ovsthread_once)
OVSTHREAD_ONCE_INITIALIZER;
+ offload_dummy->flow_mark_pool = NULL;
+ offload_dummy->unreference_cb = NULL;
*dpif_offload = &offload_dummy->offload;
return 0;
@@ -185,6 +473,9 @@ dpif_offload_dummy_close(struct dpif_offload *dpif_offload)
dpif_offload);
dpif_offload_port_mgr_uninit(offload_dummy->port_mgr);
+ if (offload_dummy->flow_mark_pool) {
+ id_fpool_destroy(offload_dummy->flow_mark_pool);
+ }
free(offload_dummy);
}
@@ -297,26 +588,295 @@ dpif_offload_dummy_can_offload(struct dpif_offload *dpif_offload OVS_UNUSED,
return is_dummy_netdev_class(netdev->netdev_class) ? true : false;
}
-#define DEFINE_DPIF_DUMMY_CLASS(NAME, TYPE_STR) \
- struct dpif_offload_class NAME = { \
- .type = TYPE_STR, \
- .impl_type = DPIF_OFFLOAD_IMPL_HW_ONLY, \
- .supported_dpif_types = (const char *const[]) { \
- "dummy", \
- NULL}, \
- .open = dpif_offload_dummy_open, \
- .close = dpif_offload_dummy_close, \
- .set_config = dpif_offload_dummy_set_config, \
- .get_debug = dpif_offload_dummy_get_debug, \
- .get_global_stats = dpif_offload_dummy_get_global_stats, \
- .can_offload = dpif_offload_dummy_can_offload, \
- .port_add = dpif_offload_dummy_port_add, \
- .port_del = dpif_offload_dummy_port_del, \
- .port_dump_start = dpif_offload_dummy_port_dump_start, \
- .port_dump_next = dpif_offload_dummy_port_dump_next, \
- .port_dump_done = dpif_offload_dummy_port_dump_done, \
- .get_netdev = dpif_offload_dummy_get_netdev, \
+static void
+dpif_offload_dummy_log_operation(const char *op, int error,
+ const ovs_u128 *ufid)
+{
+ VLOG_DBG("%s to %s netdev flow "UUID_FMT,
+ error == 0 ? "succeed" : "failed", op,
+ UUID_ARGS((struct uuid *) ufid));
+}
+
+static struct dpif_offload_dummy_port *
+dpif_offload_dummy_get_port_by_netdev(const struct dpif_offload *offload_,
+ struct netdev *netdev)
+{
+ struct dpif_offload_dummy *offload = dpif_offload_dummy_cast(offload_);
+ struct dpif_offload_port_mgr_port *port;
+
+ port = dpif_offload_port_mgr_find_by_netdev(offload->port_mgr, netdev);
+ if (!port) {
+ return NULL;
+ }
+ return dpif_offload_dummy_cast_port(port);
+}
+
+static int
+dpif_offload_dummy_netdev_flow_put(const struct dpif_offload *offload_,
+ struct netdev *netdev,
+ struct dpif_offload_flow_put *put,
+ void **previous_flow_reference)
+{
+ struct dpif_offload_dummy *offload = dpif_offload_dummy_cast(offload_);
+ struct dummy_offloaded_flow *off_flow;
+ struct dpif_offload_dummy_port *port;
+ bool modify = true;
+ int error = 0;
+
+ port = dpif_offload_dummy_get_port_by_netdev(offload_, netdev);
+ if (!port) {
+ error = ENODEV;
+ goto exit;
+ }
+
+ ovs_mutex_lock(&port->port_mutex);
+
+ off_flow = dpif_offload_dummy_find_offloaded_flow_and_update(
+ port, put->ufid, put->pmd_id, put->flow_reference,
+ previous_flow_reference);
+
+ if (!off_flow) {
+ /* Create new offloaded flow. */
+ uint32_t mark = dpif_offload_dummy_allocate_flow_mark(offload);
+
+ if (mark == INVALID_FLOW_MARK) {
+ error = ENOSPC;
+ goto exit_unlock;
+ }
+
+ off_flow = dpif_offload_dummy_add_flow(port, put->ufid, put->pmd_id,
+ put->flow_reference, mark);
+ modify = false;
+ *previous_flow_reference = NULL;
+ }
+ memcpy(&off_flow->match, put->match, sizeof *put->match);
+
+ /* As we have per-netdev 'offloaded_flows', we don't need to match
+ * the 'in_port' for received packets. This will also allow offloading
+ * for packets passed to 'receive' command without specifying the
+ * 'in_port'. */
+ off_flow->match.wc.masks.in_port.odp_port = 0;
+
+ if (VLOG_IS_DBG_ENABLED()) {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+
+ ds_put_format(&ds, "%s: flow put[%s]: ", netdev_get_name(netdev),
+ modify ? "modify" : "create");
+ odp_format_ufid(put->ufid, &ds);
+ ds_put_cstr(&ds, " flow match: ");
+ match_format(put->match, NULL, &ds, OFP_DEFAULT_PRIORITY);
+ ds_put_format(&ds, ", mark: %"PRIu32, off_flow->mark);
+
+ VLOG_DBG("%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+ }
+
+exit_unlock:
+ ovs_mutex_unlock(&port->port_mutex);
+
+exit:
+ if (put->stats) {
+ memset(put->stats, 0, sizeof *put->stats);
+ }
+
+ dpif_offload_dummy_log_operation(modify ? "modify" : "add", error,
+ put->ufid);
+ return error;
+}
+
+static int
+dpif_offload_dummy_netdev_flow_del(const struct dpif_offload *offload_,
+ struct netdev *netdev,
+ struct dpif_offload_flow_del *del)
+{
+ struct dpif_offload_dummy *offload = dpif_offload_dummy_cast(offload_);
+ struct dummy_offloaded_flow *off_flow;
+ struct dpif_offload_dummy_port *port;
+ uint32_t mark = INVALID_FLOW_MARK;
+ const char *error = NULL;
+
+ port = dpif_offload_dummy_get_port_by_netdev(offload_, netdev);
+ if (!port) {
+ error = "No such (net)device.";
+ goto exit;
+ }
+
+ ovs_mutex_lock(&port->port_mutex);
+
+ off_flow = dpif_offload_dummy_find_offloaded_flow(port, del->ufid);
+ if (!off_flow) {
+ error = "No such flow.";
+ goto exit_unlock;
+ }
+
+ if (!dpif_offload_dummy_del_flow_pmd_data(port, off_flow, del->pmd_id,
+ del->flow_reference)) {
+ error = "No such flow with pmd_id and reference.";
+ goto exit_unlock;
+ }
+
+ mark = off_flow->mark;
+ if (!hmap_count(&off_flow->pmd_id_map)) {
+ dpif_offload_dummy_free_flow_mark(offload, mark);
+ dpif_offload_dummy_free_flow(port, off_flow, true);
+ }
+
+exit_unlock:
+ ovs_mutex_unlock(&port->port_mutex);
+
+exit:
+ if (error || VLOG_IS_DBG_ENABLED()) {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+
+ ds_put_format(&ds, "%s: ", netdev_get_name(netdev));
+ if (error) {
+ ds_put_cstr(&ds, "failed to ");
+ }
+ ds_put_cstr(&ds, "flow del: ");
+ odp_format_ufid(del->ufid, &ds);
+ if (error) {
+ ds_put_format(&ds, " error: %s", error);
+ } else {
+ ds_put_format(&ds, " mark: %"PRIu32, mark);
+ }
+ VLOG(error ? VLL_WARN : VLL_DBG, "%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+ }
+
+ if (del->stats) {
+ memset(del->stats, 0, sizeof *del->stats);
+ }
+
+ dpif_offload_dummy_log_operation("delete", error ? -1 : 0, del->ufid);
+ return error ? ENOENT : 0;
+}
+
+static bool
+dpif_offload_dummy_netdev_flow_stats(const struct dpif_offload *offload_,
+ struct netdev *netdev,
+ const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats,
+ struct dpif_flow_attrs *attrs)
+{
+ struct dummy_offloaded_flow *off_flow = NULL;
+ struct dpif_offload_dummy_port *port;
+
+ port = dpif_offload_dummy_get_port_by_netdev(offload_, netdev);
+ if (!port) {
+ return false;
}
+ ovs_mutex_lock(&port->port_mutex);
+ off_flow = dpif_offload_dummy_find_offloaded_flow(port, ufid);
+ ovs_mutex_unlock(&port->port_mutex);
+
+ memset(stats, 0, sizeof *stats);
+ attrs->offloaded = off_flow ? true : false;
+ attrs->dp_layer = "tc";
+ attrs->dp_extra_info = NULL;
+
+ return off_flow ? true : false;
+}
+
+static void
+dpif_offload_dummy_register_flow_unreference_cb(
+ const struct dpif_offload *offload_, dpif_offload_flow_unreference_cb *cb)
+{
+ struct dpif_offload_dummy *offload = dpif_offload_dummy_cast(offload_);
+
+ offload->unreference_cb = cb;
+}
+
+static void
+dpif_offload_dummy_flow_unreference(struct dpif_offload_dummy *offload,
+ unsigned pmd_id, void *flow_reference)
+{
+ if (offload->unreference_cb) {
+ offload->unreference_cb(pmd_id, flow_reference);
+ }
+}
+
+void
+dpif_offload_dummy_netdev_simulate_offload(struct netdev *netdev,
+ struct dp_packet *packet,
+ struct flow *flow)
+{
+ const struct dpif_offload *offload_ = ovsrcu_get(
+ const struct dpif_offload *, &netdev->dpif_offload);
+ struct dpif_offload_dummy_port *port;
+ struct dummy_offloaded_flow *data;
+ struct flow packet_flow;
+
+ if (!offload_ || strcmp(dpif_offload_class_type(offload_), "dummy")) {
+ return;
+ }
+
+ port = dpif_offload_dummy_get_port_by_netdev(offload_, netdev);
+ if (!port) {
+ return;
+ }
+
+ if (!flow) {
+ flow = &packet_flow;
+ flow_extract(packet, flow);
+ }
+
+ ovs_mutex_lock(&port->port_mutex);
+ HMAP_FOR_EACH (data, node, &port->offloaded_flows) {
+ if (flow_equal_except(flow, &data->match.flow, &data->match.wc)) {
+
+ dp_packet_set_flow_mark(packet, data->mark);
+
+ if (VLOG_IS_DBG_ENABLED()) {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+
+ ds_put_format(&ds, "%s: packet: ",
+ netdev_get_name(netdev));
+ /* 'flow' does not contain proper port number here.
+ * Let's just clear it as it's wildcarded anyway. */
+ flow->in_port.ofp_port = 0;
+ flow_format(&ds, flow, NULL);
+
+ ds_put_cstr(&ds, " matches with flow: ");
+ odp_format_ufid(&data->ufid, &ds);
+ ds_put_cstr(&ds, " ");
+ match_format(&data->match, NULL, &ds, OFP_DEFAULT_PRIORITY);
+ ds_put_format(&ds, " with mark: %"PRIu32, data->mark);
+
+ VLOG_DBG("%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+ }
+ break;
+ }
+ }
+ ovs_mutex_unlock(&port->port_mutex);
+}
+
+#define DEFINE_DPIF_DUMMY_CLASS(NAME, TYPE_STR) \
+ struct dpif_offload_class NAME = { \
+ .type = TYPE_STR, \
+ .impl_type = DPIF_OFFLOAD_IMPL_HW_ONLY, \
+ .supported_dpif_types = (const char *const[]){ \
+ "dummy", \
+ NULL}, \
+ .open = dpif_offload_dummy_open, \
+ .close = dpif_offload_dummy_close, \
+ .set_config = dpif_offload_dummy_set_config, \
+ .get_debug = dpif_offload_dummy_get_debug, \
+ .get_global_stats = dpif_offload_dummy_get_global_stats, \
+ .can_offload = dpif_offload_dummy_can_offload, \
+ .port_add = dpif_offload_dummy_port_add, \
+ .port_del = dpif_offload_dummy_port_del, \
+ .port_dump_start = dpif_offload_dummy_port_dump_start, \
+ .port_dump_next = dpif_offload_dummy_port_dump_next, \
+ .port_dump_done = dpif_offload_dummy_port_dump_done, \
+ .get_netdev = dpif_offload_dummy_get_netdev, \
+ .netdev_flow_put = dpif_offload_dummy_netdev_flow_put, \
+ .netdev_flow_del = dpif_offload_dummy_netdev_flow_del, \
+ .netdev_flow_stats = dpif_offload_dummy_netdev_flow_stats, \
+ .register_flow_unreference_cb = \
+ dpif_offload_dummy_register_flow_unreference_cb, \
+}
+
DEFINE_DPIF_DUMMY_CLASS(dpif_offload_dummy_class, "dummy");
DEFINE_DPIF_DUMMY_CLASS(dpif_offload_dummy_x_class, "dummy_x");
diff --git a/lib/dummy.h b/lib/dummy.h
index f0eb30ee2..266c200c3 100644
--- a/lib/dummy.h
+++ b/lib/dummy.h
@@ -20,6 +20,9 @@
#include <stdbool.h>
struct netdev_class;
+struct dp_packet;
+struct netdev;
+struct flow;
/* Degree of dummy support.
*
@@ -41,5 +44,8 @@ void netdev_dummy_register(enum dummy_level);
void timeval_dummy_register(void);
void ofpact_dummy_enable(void);
bool is_dummy_netdev_class(const struct netdev_class *);
+void dpif_offload_dummy_netdev_simulate_offload(struct netdev *,
+ struct dp_packet *,
+ struct flow *);
#endif /* dummy.h */
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 6a99f4ced..b0eb27383 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1808,7 +1808,7 @@ netdev_dummy_queue_packet__(struct netdev_rxq_dummy *rx,
struct dp_packet *packe
static void
netdev_dummy_queue_packet(struct netdev_dummy *dummy, struct dp_packet
*packet,
- struct flow *flow OVS_UNUSED, int queue_id)
+ struct flow *flow, int queue_id)
OVS_REQUIRES(dummy->mutex)
{
struct netdev_rxq_dummy *rx, *prev;
@@ -1817,6 +1817,8 @@ netdev_dummy_queue_packet(struct netdev_dummy *dummy,
struct dp_packet *packet,
ovs_pcap_write(dummy->rxq_pcap, packet);
}
+ dpif_offload_dummy_netdev_simulate_offload(&dummy->up, packet, flow);
+
prev = NULL;
LIST_FOR_EACH (rx, node, &dummy->rxes) {
if (rx->up.queue_id == queue_id &&
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index 839648d96..e17a16de2 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -37,15 +37,17 @@ filter_flow_install () {
}
filter_hw_flow_install () {
- grep 'netdev_dummy.*flow put\[create\]' | sed 's/.*|DBG|//' | sort | uniq
+ grep 'dpif_offload_dummy.*flow put\[create\]' | sed 's/.*|DBG|//' | sort \
+ | uniq
}
filter_hw_flow_del () {
- grep 'netdev_dummy.*flow del' | sed 's/.*|DBG|//' | sort | uniq
+ grep 'dpif_offload_dummy.*flow del' | sed 's/.*|DBG|//' | sort | uniq
}
filter_hw_packet_netdev_dummy () {
- grep 'netdev_dummy.*: packet:.*with mark' | sed 's/.*|DBG|//' | sort | uniq
+ grep 'dpif_offload_dummy.*: packet:.*with mark' | sed 's/.*|DBG|//' \
+ | sort | uniq
}
filter_flow_dump () {
@@ -411,7 +413,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD],
set bridge br0 datapath-type=dummy \
other-config:datapath-id=1234 fail-mode=secure], [], [],
[m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])])
- AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
netdev_dummy:file:dbg])
+ AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
dpif_offload_dummy:file:dbg])
AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
@@ -462,11 +464,8 @@ p1: flow del: mark: 1
OVS_VSWITCHD_STOP
AT_CLEANUP])
-# XXX: Remove these tests for now as we do not have a dummy implementation
-# to add flows. See netdev_offload_dummy. We will fix and re-add later.
-# DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy])
-# DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy-pmd])
-
+DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy])
+DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy-pmd])
m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS],
[AT_SETUP([dpif-netdev - partial hw offload with packet modifications - $1])
@@ -476,7 +475,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS],
set bridge br0 datapath-type=dummy \
other-config:datapath-id=1234 fail-mode=secure], [], [],
[m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])])
- AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
netdev_dummy:file:dbg])
+ AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
dpif_offload_dummy:file:dbg])
AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
@@ -542,10 +541,8 @@
udp,in_port=ANY,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:
OVS_VSWITCHD_STOP
AT_CLEANUP])
-# XXX: Remove these tests for now as we do not have a dummy implementation
-# to add flows. See netdev_offload_dummy. We will fix and re-add later.
-# DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy])
-# DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy-pmd])
+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy])
+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy-pmd])
m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP],
[AT_SETUP([dpif-netdev - partial hw offload with arp vlan id packet
modifications - $1])
@@ -555,7 +552,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP],
set bridge br0 datapath-type=dummy \
other-config:datapath-id=1234 fail-mode=secure], [], [],
[m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])])
- AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
netdev_dummy:file:dbg])
+ AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
dpif_offload_dummy:file:dbg])
AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
@@ -621,10 +618,8 @@
arp,in_port=ANY,dl_vlan=11,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:
OVS_VSWITCHD_STOP
AT_CLEANUP])
-# XXX: Remove these tests for now as we do not have a dummy implementation
-# to add flows. See netdev_offload_dummy. We will fix and re-add later.
-# DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy])
-# DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy-pmd])
+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy])
+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy-pmd])
AT_SETUP([dpif-netdev - check dpctl/add-flow in_port exact match])
OVS_VSWITCHD_START(