In this patch, we support offloading of VXLAN_ENCAP action for a vhost-user
port (aka "partial-action-offload"). At the time of offloading the flow, we
determine if the flow can be offloaded to an egress device, if the input
port is not offload capable such as a vhost-user port. We then offload the
flow with a VXLAN_ENCAP RTE action, to the egress device. We do not add
the OUTPUT RTE action, which indicates to the PMD that is is a partial
action offload request. Note that since the action is being offloaded in
egress direction, classification is expected to be done by OVS SW datapath
and hence there's no need to offload a MARK action.
If offload succeeds, we save the information in 'dp_netdev_flow' so that
we skip execution of the corresponding action (previous patch) during SW
datapath processing.
Reviewed-by: Hemal Shah
Signed-off-by: Sriharsha Basavapatna
---
lib/dpif-netdev.c | 105 ++---
lib/netdev-offload-dpdk.c | 204 ++
lib/netdev-offload-provider.h | 7 ++
lib/netdev-offload.c | 67 +++
lib/netdev-offload.h | 8 +-
5 files changed, 355 insertions(+), 36 deletions(-)
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 2c20e6d5e..a0bb5d4e1 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2505,10 +2505,49 @@ dp_netdev_append_flow_offload(struct
dp_flow_offload_item *offload)
ovs_mutex_unlock(_flow_offload.mutex);
}
+static int
+partial_offload_egress_flow_del(struct dp_flow_offload_item *offload)
+{
+struct dp_netdev_pmd_thread *pmd = offload->pmd;
+struct dp_netdev_flow *flow = offload->flow;
+const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type);
+struct netdev *port;
+int ret;
+
+port = netdev_ports_get(flow->egress_offload_port, dpif_type_str);
+if (!port) {
+return -1;
+}
+
+/* Taking a global 'port_mutex' to fulfill thread safety
+ * restrictions for the netdev-offload-dpdk module. */
+ovs_mutex_lock(>dp->port_mutex);
+ret = netdev_flow_del(port, >mega_ufid, NULL);
+ovs_mutex_unlock(>dp->port_mutex);
+netdev_close(port);
+
+if (ret) {
+return ret;
+}
+
+flow->egress_offload_port = NULL;
+flow->partial_actions_offloaded = false;
+
+VLOG_DBG_RL("%s: flow: %p mega_ufid: "UUID_FMT" pmd_id: %d\n", __func__,
+flow, UUID_ARGS((struct uuid *)>mega_ufid),
+offload->flow->pmd_id);
+return ret;
+}
+
static int
dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload)
{
-return mark_to_flow_disassociate(offload->pmd, offload->flow);
+if (unlikely(offload->flow->partial_actions_offloaded &&
+offload->flow->egress_offload_port != ODPP_NONE)) {
+return partial_offload_egress_flow_del(offload);
+} else {
+return mark_to_flow_disassociate(offload->pmd, offload->flow);
+}
}
static int
@@ -2568,51 +2607,82 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item
*offload)
const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type);
bool modification = offload->op == DP_NETDEV_FLOW_OFFLOAD_OP_MOD;
struct offload_info info;
-struct netdev *port;
-uint32_t mark;
+struct netdev *netdev;
+odp_port_t egress_port = ODPP_NONE;
+struct netdev *egress_netdev = NULL;
+bool alloc_mark = true;
+uint32_t mark = INVALID_FLOW_MARK;
int ret;
if (flow->dead) {
return -1;
}
-port = netdev_ports_get(in_port, dpif_type_str);
-if (!port) {
+netdev = netdev_ports_get(in_port, dpif_type_str);
+if (!netdev) {
return -1;
}
-if (dp_netdev_alloc_flow_mark(flow, modification, )) {
+info.attr_egress = 0;
+info.partial_actions = 0;
+
+if (unlikely(netdev_partial_offload_egress(netdev, dpif_type_str,
+ >match,
+ CONST_CAST(struct nlattr *,
+ offload->actions),
+ offload->actions_len,
+ _netdev,
+ _port))) {
+if (egress_netdev) {
+netdev_close(netdev);
+netdev = egress_netdev;
+flow->egress_offload_port = egress_port;
+info.attr_egress = 1;
+alloc_mark = false;
+}
+info.partial_actions = 1;
+}
+
+if (alloc_mark && dp_netdev_alloc_flow_mark(flow, modification, )) {
/* flow already offloaded */
-netdev_close(port);
-return 0;
+netdev_close(netdev);
+return 0;
}
+
info.flow_mark = mark;
/* Taking a global 'port_mutex' to fulfill thread safety restrictions for
* the netdev-offload-dpdk module. */
ovs_mutex_lock(>dp->port_mutex);
-ret = netdev_flow_put(port,