kni: restrict bifurcated device support

To enable bifurcated device support, rtnl_lock is released before calling
userspace callbacks and asynchronous requests are enabled.

But these changes caused more issues, like bug #809, #816. To reduce the
scope of the problems, the bifurcated device support related changes are
only enabled when it is requested explicitly with new 'enable_bifurcated'
module parameter.
And bifurcated device support is disabled by default.

So the bifurcated device related problems are isolated and they can be
fixed without impacting all use cases.

Bugzilla ID: 816
Fixes: 631217c761 ("kni: fix kernel deadlock with bifurcated device")
Cc: stable@dpdk.org

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Igor Ryzhov <iryzhov@nfware.com>
This commit is contained in:
Ferruh Yigit 2021-11-23 16:46:17 +00:00 committed by Thomas Monjalon
parent 0f4611cc26
commit a1b2558cdb
5 changed files with 98 additions and 17 deletions

View File

@ -56,6 +56,12 @@ can be specified when the module is loaded to control its behavior:
off Interfaces will be created with carrier state set to off. off Interfaces will be created with carrier state set to off.
on Interfaces will be created with carrier state set to on. on Interfaces will be created with carrier state set to on.
(charp) (charp)
parm: enable_bifurcated: Enable request processing support for
bifurcated drivers, which means releasing rtnl_lock before calling
userspace callback and supporting async requests (default=off):
on Enable request processing support for bifurcated drivers.
(charp)
Loading the ``rte_kni`` kernel module without any optional parameters is Loading the ``rte_kni`` kernel module without any optional parameters is
the typical way a DPDK application gets packets into and out of the kernel the typical way a DPDK application gets packets into and out of the kernel
@ -174,6 +180,28 @@ To set the default carrier state to *off*:
If the ``carrier`` parameter is not specified, the default carrier state If the ``carrier`` parameter is not specified, the default carrier state
of KNI interfaces will be set to *off*. of KNI interfaces will be set to *off*.
.. _kni_bifurcated_device_support:
Bifurcated Device Support
~~~~~~~~~~~~~~~~~~~~~~~~~
User callbacks are executed while kernel module holds the ``rtnl`` lock, this
causes a deadlock when callbacks run control commands on another Linux kernel
network interface.
Bifurcated devices has kernel network driver part and to prevent deadlock for
them ``enable_bifurcated`` is used.
To enable bifurcated device support:
.. code-block:: console
# insmod <build_dir>/kernel/linux/kni/rte_kni.ko enable_bifurcated=on
Enabling bifurcated device support releases ``rtnl`` lock before calling
callback and locks it back after callback. Also enables asynchronous request to
support callbacks that requires rtnl lock to work (interface down).
KNI Creation and Deletion KNI Creation and Deletion
------------------------- -------------------------

View File

@ -75,6 +75,12 @@ New Features
operations. operations.
* Added multi-process support. * Added multi-process support.
* **Updated default KNI behavior on net devices control callbacks.**
Updated KNI net devices control callbacks to run with ``rtnl`` kernel lock
held by default. A newly added ``enable_bifurcated`` KNI kernel module
parameter can be used to run callbacks with ``rtnl`` lock released.
* **Added HiSilicon DMA driver.** * **Added HiSilicon DMA driver.**
The HiSilicon DMA driver provides device drivers for the Kunpeng's DMA devices. The HiSilicon DMA driver provides device drivers for the Kunpeng's DMA devices.

View File

@ -34,6 +34,9 @@
/* Default carrier state for created KNI network interfaces */ /* Default carrier state for created KNI network interfaces */
extern uint32_t kni_dflt_carrier; extern uint32_t kni_dflt_carrier;
/* Request processing support for bifurcated drivers. */
extern uint32_t bifurcated_support;
/** /**
* A structure describing the private information for a kni device. * A structure describing the private information for a kni device.
*/ */

View File

@ -41,6 +41,10 @@ static uint32_t multiple_kthread_on;
static char *carrier; static char *carrier;
uint32_t kni_dflt_carrier; uint32_t kni_dflt_carrier;
/* Request processing support for bifurcated drivers. */
static char *enable_bifurcated;
uint32_t bifurcated_support;
#define KNI_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */ #define KNI_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */
static int kni_net_id; static int kni_net_id;
@ -565,6 +569,22 @@ kni_parse_carrier_state(void)
return 0; return 0;
} }
static int __init
kni_parse_bifurcated_support(void)
{
if (!enable_bifurcated) {
bifurcated_support = 0;
return 0;
}
if (strcmp(enable_bifurcated, "on") == 0)
bifurcated_support = 1;
else
return -1;
return 0;
}
static int __init static int __init
kni_init(void) kni_init(void)
{ {
@ -590,6 +610,13 @@ kni_init(void)
else else
pr_debug("Default carrier state set to on.\n"); pr_debug("Default carrier state set to on.\n");
if (kni_parse_bifurcated_support() < 0) {
pr_err("Invalid parameter for bifurcated support\n");
return -EINVAL;
}
if (bifurcated_support == 1)
pr_debug("bifurcated support is enabled.\n");
#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS #ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS
rc = register_pernet_subsys(&kni_net_ops); rc = register_pernet_subsys(&kni_net_ops);
#else #else
@ -656,3 +683,12 @@ MODULE_PARM_DESC(carrier,
"\t\ton Interfaces will be created with carrier state set to on.\n" "\t\ton Interfaces will be created with carrier state set to on.\n"
"\t\t" "\t\t"
); );
module_param(enable_bifurcated, charp, 0644);
MODULE_PARM_DESC(enable_bifurcated,
"Enable request processing support for bifurcated drivers, "
"which means releasing rtnl_lock before calling userspace callback and "
"supporting async requests (default=off):\n"
"\t\ton Enable request processing support for bifurcated drivers.\n"
"\t\t"
);

View File

@ -113,12 +113,14 @@ kni_net_process_request(struct net_device *dev, struct rte_kni_request *req)
ASSERT_RTNL(); ASSERT_RTNL();
/* If we need to wait and RTNL mutex is held if (bifurcated_support) {
* drop the mutex and hold reference to keep device /* If we need to wait and RTNL mutex is held
*/ * drop the mutex and hold reference to keep device
if (req->async == 0) { */
dev_hold(dev); if (req->async == 0) {
rtnl_unlock(); dev_hold(dev);
rtnl_unlock();
}
} }
mutex_lock(&kni->sync_lock); mutex_lock(&kni->sync_lock);
@ -132,12 +134,14 @@ kni_net_process_request(struct net_device *dev, struct rte_kni_request *req)
goto fail; goto fail;
} }
/* No result available since request is handled if (bifurcated_support) {
* asynchronously. set response to success. /* No result available since request is handled
*/ * asynchronously. set response to success.
if (req->async != 0) { */
req->result = 0; if (req->async != 0) {
goto async; req->result = 0;
goto async;
}
} }
ret_val = wait_event_interruptible_timeout(kni->wq, ret_val = wait_event_interruptible_timeout(kni->wq,
@ -160,9 +164,11 @@ kni_net_process_request(struct net_device *dev, struct rte_kni_request *req)
fail: fail:
mutex_unlock(&kni->sync_lock); mutex_unlock(&kni->sync_lock);
if (req->async == 0) { if (bifurcated_support) {
rtnl_lock(); if (req->async == 0) {
dev_put(dev); rtnl_lock();
dev_put(dev);
}
} }
return ret; return ret;
} }
@ -207,8 +213,10 @@ kni_net_release(struct net_device *dev)
/* Setting if_up to 0 means down */ /* Setting if_up to 0 means down */
req.if_up = 0; req.if_up = 0;
/* request async because of the deadlock problem */ if (bifurcated_support) {
req.async = 1; /* request async because of the deadlock problem */
req.async = 1;
}
ret = kni_net_process_request(dev, &req); ret = kni_net_process_request(dev, &req);