diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index fff57f78279a..d6f2f0517da6 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -437,6 +437,7 @@ enum dpdk_hw_ol_features {
 struct netdev_dpdk {
     PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0,
         dpdk_port_t port_id;
+        dpdk_port_t flow_transfer_proxy_port_id;
 
         /* If true, device was attached by rte_eth_dev_attach(). */
         bool attached;
@@ -1155,6 +1156,24 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
     uint32_t rx_chksm_offload_capa = RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
                                      RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
                                      RTE_ETH_RX_OFFLOAD_IPV4_CKSUM;
+    int ret;
+
+    /* Managing "transfer" flows requires that the user communicate them
+     * via a port which has the privilege to control the embedded switch.
+     * For some vendors, all ports in a given switching domain have
+     * this privilege. For other vendors, it's only one port.
+     *
+     * Get the proxy port ID and remember it for later use.
+     */
+    ret = rte_flow_pick_transfer_proxy(dev->port_id,
+                                       &dev->flow_transfer_proxy_port_id,
+                                       NULL);
+    if (ret != 0) {
+        /* The PMD does not indicate the proxy port.
+         * Assume the proxy is unneeded.
+         */
+        dev->flow_transfer_proxy_port_id = dev->port_id;
+    }
 
     rte_eth_dev_info_get(dev->port_id, &info);
 
@@ -3769,6 +3788,7 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED,
     struct ds used_interfaces = DS_EMPTY_INITIALIZER;
     struct rte_eth_dev_info dev_info;
     dpdk_port_t sibling_port_id;
+    struct netdev_dpdk *dev;
     dpdk_port_t port_id;
     bool used = false;
     char *response;
@@ -3786,8 +3806,6 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED,
                   argv[1]);
 
     RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, port_id) {
-        struct netdev_dpdk *dev;
-
         LIST_FOR_EACH (dev, list_node, &dpdk_list) {
             if (dev->port_id != sibling_port_id) {
                 continue;
@@ -3807,6 +3825,17 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED,
     }
     ds_destroy(&used_interfaces);
 
+    /* The device being detached may happen to be a flow proxy port
+     * for another device (still attached). Update the flow proxy port id,
+     * indicate that the device being detached no longer needs a flow proxy.
+     */
+    LIST_FOR_EACH (dev, list_node, &dpdk_list) {
+        if (dev->port_id == port_id) {
+            dev->flow_transfer_proxy_port_id = port_id;
+            break;
+        }
+    }
+
     rte_eth_dev_info_get(port_id, &dev_info);
     rte_eth_dev_close(port_id);
     if (rte_dev_remove(dev_info.device) < 0) {
@@ -3817,6 +3846,16 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED,
     response = xasprintf("All devices shared with device '%s' "
                          "have been detached", argv[1]);
 
+    /* The device being detached may happen to be a flow proxy port.
+     * After the flow proxy port was detached, the related ports
+     * will reconfigure the device and update the proxy_port_id.
+     */
+    LIST_FOR_EACH (dev, list_node, &dpdk_list) {
+         if (dev->flow_transfer_proxy_port_id == port_id) {
+                netdev_request_reconfigure(&dev->up);
+        }
+    }
+
     ovs_mutex_unlock(&dpdk_mutex);
     unixctl_command_reply(conn, response);
     free(response);
@@ -5192,6 +5231,23 @@ out:
     return ret;
 }
 
+int
+netdev_dpdk_get_prox_port_id(struct netdev *netdev)
+{
+    struct netdev_dpdk *dev;
+    int ret = -1;
+
+    if (!is_dpdk_class(netdev->netdev_class)) {
+        return ret;
+    }
+
+    dev = netdev_dpdk_cast(netdev);
+    ovs_mutex_lock(&dev->mutex);
+    ret = dev->flow_transfer_proxy_port_id;
+    ovs_mutex_unlock(&dev->mutex);
+    return ret;
+}
+
 bool
 netdev_dpdk_flow_api_supported(struct netdev *netdev)
 {
diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h
index 5cd95d00f5a5..277db156fe06 100644
--- a/lib/netdev-dpdk.h
+++ b/lib/netdev-dpdk.h
@@ -51,6 +51,8 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev,
                                  struct rte_flow_error *error);
 int
 netdev_dpdk_get_port_id(struct netdev *netdev);
+int
+netdev_dpdk_get_prox_port_id(struct netdev *netdev);
 
 #ifdef ALLOW_EXPERIMENTAL_API
 
