]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
RDMA/core: Add command to set ib_core device net namspace sharing mode
authorParav Pandit <parav@mellanox.com>
Tue, 26 Feb 2019 12:01:49 +0000 (14:01 +0200)
committerJason Gunthorpe <jgg@mellanox.com>
Thu, 28 Mar 2019 17:52:02 +0000 (14:52 -0300)
Add netlink command that enables/disables sharing rdma device among
multiple net namespaces.

Using rdma tool,
$rdma sys set netns shared (default mode)

When rdma subsystem netns mode is set to shared mode, rdma devices
will be accessible in all net namespaces.

Using rdma tool,
$rdma sys set netns exclusive

When rdma subsystem netns mode is set to exclusive mode, devices
will be accessible in only one net namespace at any given
point of time.

If there are any net namespaces other than default init_net exists,
while executing this command, it will fail and mode cannot be changed.

To change this mode, netlink command is used instead of sysctl, because
netlink command allows to auto load a module.

Signed-off-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/nldev.c
include/uapi/rdma/rdma_netlink.h

index 30c7d4a46b76283b32448718ae5b43c9aca62866..0663fc64e9506b8af4856792121c724e986f546d 100644 (file)
@@ -342,4 +342,6 @@ struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr);
 void ib_free_port_attrs(struct ib_core_device *coredev);
 int ib_setup_port_attrs(struct ib_core_device *coredev,
                        bool alloc_hw_stats);
+
+int rdma_compatdev_set(u8 enable);
 #endif /* _CORE_PRIV_H */
index 0605208a73d321e4e8b2925017ba0d69a4648e78..2dbd04739ac6d5ed8e997ea3f33beb6ad5287ed1 100644 (file)
@@ -766,6 +766,7 @@ static int add_one_compat_dev(struct ib_device *device,
        struct ib_core_device *cdev;
        int ret;
 
+       lockdep_assert_held(&rdma_nets_rwsem);
        if (!ib_devices_shared_netns)
                return 0;
 
@@ -870,6 +871,87 @@ static int add_compat_devs(struct ib_device *device)
        return ret;
 }
 
+static void remove_all_compat_devs(void)
+{
+       struct ib_compat_device *cdev;
+       struct ib_device *dev;
+       unsigned long index;
+
+       down_read(&devices_rwsem);
+       xa_for_each (&devices, index, dev) {
+               unsigned long c_index = 0;
+
+               /* Hold nets_rwsem so that any other thread modifying this
+                * system param can sync with this thread.
+                */
+               down_read(&rdma_nets_rwsem);
+               xa_for_each (&dev->compat_devs, c_index, cdev)
+                       remove_one_compat_dev(dev, c_index);
+               up_read(&rdma_nets_rwsem);
+       }
+       up_read(&devices_rwsem);
+}
+
+static int add_all_compat_devs(void)
+{
+       struct rdma_dev_net *rnet;
+       struct ib_device *dev;
+       unsigned long index;
+       int ret = 0;
+
+       down_read(&devices_rwsem);
+       xa_for_each_marked (&devices, index, dev, DEVICE_REGISTERED) {
+               unsigned long net_index = 0;
+
+               /* Hold nets_rwsem so that any other thread modifying this
+                * system param can sync with this thread.
+                */
+               down_read(&rdma_nets_rwsem);
+               xa_for_each (&rdma_nets, net_index, rnet) {
+                       ret = add_one_compat_dev(dev, rnet);
+                       if (ret)
+                               break;
+               }
+               up_read(&rdma_nets_rwsem);
+       }
+       up_read(&devices_rwsem);
+       if (ret)
+               remove_all_compat_devs();
+       return ret;
+}
+
+int rdma_compatdev_set(u8 enable)
+{
+       struct rdma_dev_net *rnet;
+       unsigned long index;
+       int ret = 0;
+
+       down_write(&rdma_nets_rwsem);
+       if (ib_devices_shared_netns == enable) {
+               up_write(&rdma_nets_rwsem);
+               return 0;
+       }
+
+       /* enable/disable of compat devices is not supported
+        * when more than default init_net exists.
+        */
+       xa_for_each (&rdma_nets, index, rnet) {
+               ret++;
+               break;
+       }
+       if (!ret)
+               ib_devices_shared_netns = enable;
+       up_write(&rdma_nets_rwsem);
+       if (ret)
+               return -EBUSY;
+
+       if (enable)
+               ret = add_all_compat_devs();
+       else
+               remove_all_compat_devs();
+       return ret;
+}
+
 static void rdma_dev_exit_net(struct net *net)
 {
        struct rdma_dev_net *rnet = net_generic(net, rdma_dev_net_id);
@@ -923,7 +1005,12 @@ static __net_init int rdma_dev_init_net(struct net *net)
 
        down_read(&devices_rwsem);
        xa_for_each_marked (&devices, index, dev, DEVICE_REGISTERED) {
+               /* Hold nets_rwsem so that netlink command cannot change
+                * system configuration for device sharing mode.
+                */
+               down_read(&rdma_nets_rwsem);
                ret = add_one_compat_dev(dev, rnet);
+               up_read(&rdma_nets_rwsem);
                if (ret)
                        break;
        }
index 49c048738f946d0f5e3677e52ab1fab9db771ce3..28b4ed8f9930e3ebbfb8ce0c154d05df25581ba2 100644 (file)
@@ -1341,6 +1341,27 @@ static int nldev_get_sys_get_dumpit(struct sk_buff *skb,
        return skb->len;
 }
 
+static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+                                 struct netlink_ext_ack *extack)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+       u8 enable;
+       int err;
+
+       err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+                         nldev_policy, extack);
+       if (err || !tb[RDMA_NLDEV_SYS_ATTR_NETNS_MODE])
+               return -EINVAL;
+
+       enable = nla_get_u8(tb[RDMA_NLDEV_SYS_ATTR_NETNS_MODE]);
+       /* Only 0 and 1 are supported */
+       if (enable > 1)
+               return -EINVAL;
+
+       err = rdma_compatdev_set(enable);
+       return err;
+}
+
 static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
        [RDMA_NLDEV_CMD_GET] = {
                .doit = nldev_get_doit,
@@ -1389,6 +1410,10 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
        [RDMA_NLDEV_CMD_SYS_GET] = {
                .dump = nldev_get_sys_get_dumpit,
        },
+       [RDMA_NLDEV_CMD_SYS_SET] = {
+               .doit = nldev_set_sys_set_doit,
+               .flags = RDMA_NL_ADMIN_PERM,
+       },
 };
 
 void __init nldev_init(void)
index 6af88c736073b83ea65c85d08989c9da9c4afe99..9bba001a734746a0616ba349e88db0100d805501 100644 (file)
@@ -262,7 +262,9 @@ enum rdma_nldev_command {
        RDMA_NLDEV_CMD_PORT_GET, /* can dump */
 
        RDMA_NLDEV_CMD_SYS_GET, /* can dump */
-       /* 7 - 8 are free to use */
+       RDMA_NLDEV_CMD_SYS_SET,
+
+       /* 8 is free to use */
 
        RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */