Add flow control API calls to the dummy offload provider, enabling the re-addition of previously disabled partial offload tests.
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( -- 2.50.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
