From 79ab2eeb16b050b62f929d678baeaa55fe88acf8 Mon Sep 17 00:00:00 2001 From: Eli Britstein Date: Sun, 11 Jun 2023 18:58:26 +0300 Subject: [PATCH] netdev-offload-dpdk: Fix flushing of a physdev. Vport's offloads are done on the tracked orig-in-port, but the flow itself is associated in the vport's map. Removing the physdev will flush all the ports that are on its map, but not the ones on other netdevs' maps. Since flows take reference count on both their vport and their physdev, the physdev still has references on. Trying to remove it and re-add it fails with "already in use" error. Fix it by flushing the physdev's offload flows in all related netdevs, e.g. the netdev itself, or for physical devices, all vports. Fixes: adbd4301a249 ("netdev-offload-dpdk: Use per-netdev offload metadata.") Reported-by: wuxi_seu@163.com Acked-by: Simon Horman Signed-off-by: Eli Britstein Signed-off-by: Ilya Maximets --- lib/netdev-offload-dpdk.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index 1ad87e5ffca..cecec071ca6 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -2526,15 +2526,15 @@ netdev_offload_dpdk_flow_get(struct netdev *netdev, return ret; } -static int -netdev_offload_dpdk_flow_flush(struct netdev *netdev) +static void +flush_netdev_flows_in_related(struct netdev *netdev, struct netdev *related) { - struct cmap *map = offload_data_map(netdev); - struct ufid_to_rte_flow_data *data; unsigned int tid = netdev_offload_thread_id(); + struct cmap *map = offload_data_map(related); + struct ufid_to_rte_flow_data *data; if (!map) { - return -1; + return; } CMAP_FOR_EACH (data, node, map) { @@ -2545,6 +2545,31 @@ netdev_offload_dpdk_flow_flush(struct netdev *netdev) netdev_offload_dpdk_flow_destroy(data); } } +} + +static bool +flush_in_vport_cb(struct netdev *vport, + odp_port_t odp_port OVS_UNUSED, + void *aux) +{ + struct netdev *netdev = aux; + + /* Only vports are related to physical devices. */ + if (netdev_vport_is_vport_class(vport->netdev_class)) { + flush_netdev_flows_in_related(netdev, vport); + } + + return false; +} + +static int +netdev_offload_dpdk_flow_flush(struct netdev *netdev) +{ + flush_netdev_flows_in_related(netdev, netdev); + + if (!netdev_vport_is_vport_class(netdev->netdev_class)) { + netdev_ports_traverse(netdev->dpif_type, flush_in_vport_cb, netdev); + } return 0; }