summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Britstein <elibr@nvidia.com>2021-07-26 11:14:54 +0300
committerIlya Maximets <i.maximets@ovn.org>2021-08-02 19:20:42 +0200
commitf7e3b47e09af7aa77c922fdb70ff0bb39551671b (patch)
treee9d53ee6a4788634c26ac63d5b73f2155bb9631e
parent350507b1633ee8fa50f42bcd7f26881cf995cb2e (diff)
downloadopenvswitch-f7e3b47e09af7aa77c922fdb70ff0bb39551671b.tar.gz
dpif-netdev: Fix offloads of modified flows.
Association of a mark to a flow is done as part of its offload handling, in the offloading thread. However, the PMD thread specifies whether an offload request is an "add" or "modify" by the association of a mark to the flow. This is exposed to a race condition. A flow might be created with actions that cannot be fully offloaded, for example flooding (before MAC learning), and later modified to have actions that can be fully offloaded. If the two requests are queued before the offload thread handling, they are both marked as "add". When the offload thread handles them, the first request is partially offloaded, and the second one is ignored as the flow is already considered as offloaded. Fix it by specifying add/modify of an offload request by the actual flow state change, without relying on the mark. Fixes: 3c7330ebf036 ("netdev-offload-dpdk: Support offload of output action.") Signed-off-by: Eli Britstein <elibr@nvidia.com> Reviewed-by: Gaetan Rivet <gaetanr@nvidia.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
-rw-r--r--lib/dpif-netdev.c14
1 files changed, 5 insertions, 9 deletions
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index d695f4d61..f60b9c2c2 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2562,10 +2562,9 @@ queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd,
static void
queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd,
struct dp_netdev_flow *flow, struct match *match,
- const struct nlattr *actions, size_t actions_len)
+ const struct nlattr *actions, size_t actions_len, int op)
{
struct dp_flow_offload_item *offload;
- int op;
if (!netdev_is_flow_api_enabled()) {
return;
@@ -2578,11 +2577,6 @@ queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd,
ovsthread_once_done(&offload_thread_once);
}
- if (flow->mark != INVALID_FLOW_MARK) {
- op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD;
- } else {
- op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD;
- }
offload = dp_netdev_alloc_flow_offload(pmd, flow, op);
offload->match = *match;
offload->actions = xmalloc(actions_len);
@@ -3454,7 +3448,8 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node),
dp_netdev_flow_hash(&flow->ufid));
- queue_netdev_flow_put(pmd, flow, match, actions, actions_len);
+ queue_netdev_flow_put(pmd, flow, match, actions, actions_len,
+ DP_NETDEV_FLOW_OFFLOAD_OP_ADD);
if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) {
struct ds ds = DS_EMPTY_INITIALIZER;
@@ -3544,7 +3539,8 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
ovsrcu_set(&netdev_flow->actions, new_actions);
queue_netdev_flow_put(pmd, netdev_flow, match,
- put->actions, put->actions_len);
+ put->actions, put->actions_len,
+ DP_NETDEV_FLOW_OFFLOAD_OP_MOD);
if (stats) {
get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL);