net/smc: introduce loopback-ism for SMC intra-OS shortcut
authorWen Gu <guwen@linux.alibaba.com>
Sun, 28 Apr 2024 06:07:29 +0000 (14:07 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 30 Apr 2024 11:24:48 +0000 (13:24 +0200)
This introduces a kind of Emulated-ISM device named loopback-ism for
SMCv2.1. The loopback-ism device is currently exclusive for SMC usage,
and aims to provide an SMC shortcut for sockets within the same kernel,
leading to improved intra-OS traffic performance. Configuration of this
feature is managed through the config SMC_LO.

Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com>
Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/smc/Kconfig
net/smc/Makefile
net/smc/af_smc.c
net/smc/smc_loopback.c [new file with mode: 0644]
net/smc/smc_loopback.h [new file with mode: 0644]

index 746be39..ba5e6a2 100644 (file)
@@ -20,3 +20,16 @@ config SMC_DIAG
          smcss.
 
          if unsure, say Y.
+
+config SMC_LO
+       bool "SMC intra-OS shortcut with loopback-ism"
+       depends on SMC
+       default n
+       help
+         SMC_LO enables the creation of an Emulated-ISM device named
+         loopback-ism in SMC and makes use of it for transferring data
+         when communication occurs within the same OS. This helps in
+         convenient testing of SMC-D since loopback-ism is independent
+         of architecture or hardware.
+
+         if unsure, say N.
index 875efcd..2c510d5 100644 (file)
@@ -6,3 +6,4 @@ smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
 smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o
 smc-y += smc_tracepoint.o
 smc-$(CONFIG_SYSCTL) += smc_sysctl.o
+smc-$(CONFIG_SMC_LO) += smc_loopback.o
index e8dcd28..47f3bc1 100644 (file)
@@ -53,6 +53,7 @@
 #include "smc_stats.h"
 #include "smc_tracepoint.h"
 #include "smc_sysctl.h"
+#include "smc_loopback.h"
 
 static DEFINE_MUTEX(smc_server_lgr_pending);   /* serialize link group
                                                 * creation on server
@@ -3555,15 +3556,23 @@ static int __init smc_init(void)
                goto out_sock;
        }
 
+       rc = smc_loopback_init();
+       if (rc) {
+               pr_err("%s: smc_loopback_init fails with %d\n", __func__, rc);
+               goto out_ib;
+       }
+
        rc = tcp_register_ulp(&smc_ulp_ops);
        if (rc) {
                pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc);
-               goto out_ib;
+               goto out_lo;
        }
 
        static_branch_enable(&tcp_have_smc);
        return 0;
 
+out_lo:
+       smc_loopback_exit();
 out_ib:
        smc_ib_unregister_client();
 out_sock:
@@ -3601,6 +3610,7 @@ static void __exit smc_exit(void)
        tcp_unregister_ulp(&smc_ulp_ops);
        sock_unregister(PF_SMC);
        smc_core_exit();
+       smc_loopback_exit();
        smc_ib_unregister_client();
        smc_ism_exit();
        destroy_workqueue(smc_close_wq);
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
new file mode 100644 (file)
index 0000000..c364e3e
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Shared Memory Communications Direct over loopback-ism device.
+ *
+ *  Functions for loopback-ism device.
+ *
+ *  Copyright (c) 2024, Alibaba Inc.
+ *
+ *  Author: Wen Gu <guwen@linux.alibaba.com>
+ *          Tony Lu <tonylu@linux.alibaba.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <net/smc.h>
+
+#include "smc_ism.h"
+#include "smc_loopback.h"
+
+static const char smc_lo_dev_name[] = "loopback-ism";
+static struct smc_lo_dev *lo_dev;
+
+static const struct smcd_ops lo_ops = {
+       .query_remote_gid       = NULL,
+       .register_dmb           = NULL,
+       .unregister_dmb         = NULL,
+       .add_vlan_id            = NULL,
+       .del_vlan_id            = NULL,
+       .set_vlan_required      = NULL,
+       .reset_vlan_required    = NULL,
+       .signal_event           = NULL,
+       .move_data              = NULL,
+       .supports_v2            = NULL,
+       .get_local_gid          = NULL,
+       .get_chid               = NULL,
+       .get_dev                = NULL,
+};
+
+static struct smcd_dev *smcd_lo_alloc_dev(const struct smcd_ops *ops,
+                                         int max_dmbs)
+{
+       struct smcd_dev *smcd;
+
+       smcd = kzalloc(sizeof(*smcd), GFP_KERNEL);
+       if (!smcd)
+               return NULL;
+
+       smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *),
+                            GFP_KERNEL);
+       if (!smcd->conn)
+               goto out_smcd;
+
+       smcd->ops = ops;
+
+       spin_lock_init(&smcd->lock);
+       spin_lock_init(&smcd->lgr_lock);
+       INIT_LIST_HEAD(&smcd->vlan);
+       INIT_LIST_HEAD(&smcd->lgr_list);
+       init_waitqueue_head(&smcd->lgrs_deleted);
+       return smcd;
+
+out_smcd:
+       kfree(smcd);
+       return NULL;
+}
+
+static int smcd_lo_register_dev(struct smc_lo_dev *ldev)
+{
+       struct smcd_dev *smcd;
+
+       smcd = smcd_lo_alloc_dev(&lo_ops, SMC_LO_MAX_DMBS);
+       if (!smcd)
+               return -ENOMEM;
+       ldev->smcd = smcd;
+       smcd->priv = ldev;
+
+       /* TODO:
+        * register loopback-ism to smcd_dev list.
+        */
+       return 0;
+}
+
+static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev)
+{
+       struct smcd_dev *smcd = ldev->smcd;
+
+       /* TODO:
+        * unregister loopback-ism from smcd_dev list.
+        */
+       kfree(smcd->conn);
+       kfree(smcd);
+}
+
+static int smc_lo_dev_init(struct smc_lo_dev *ldev)
+{
+       return smcd_lo_register_dev(ldev);
+}
+
+static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
+{
+       smcd_lo_unregister_dev(ldev);
+}
+
+static void smc_lo_dev_release(struct device *dev)
+{
+       struct smc_lo_dev *ldev =
+               container_of(dev, struct smc_lo_dev, dev);
+
+       kfree(ldev);
+}
+
+static int smc_lo_dev_probe(void)
+{
+       struct smc_lo_dev *ldev;
+       int ret;
+
+       ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+       if (!ldev)
+               return -ENOMEM;
+
+       ldev->dev.parent = NULL;
+       ldev->dev.release = smc_lo_dev_release;
+       device_initialize(&ldev->dev);
+       dev_set_name(&ldev->dev, smc_lo_dev_name);
+
+       ret = smc_lo_dev_init(ldev);
+       if (ret)
+               goto free_dev;
+
+       lo_dev = ldev; /* global loopback device */
+       return 0;
+
+free_dev:
+       put_device(&ldev->dev);
+       return ret;
+}
+
+static void smc_lo_dev_remove(void)
+{
+       if (!lo_dev)
+               return;
+
+       smc_lo_dev_exit(lo_dev);
+       put_device(&lo_dev->dev); /* device_initialize in smc_lo_dev_probe */
+}
+
+int smc_loopback_init(void)
+{
+       return smc_lo_dev_probe();
+}
+
+void smc_loopback_exit(void)
+{
+       smc_lo_dev_remove();
+}
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
new file mode 100644 (file)
index 0000000..7fc4b37
--- /dev/null
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Shared Memory Communications Direct over loopback-ism device.
+ *
+ *  SMC-D loopback-ism device structure definitions.
+ *
+ *  Copyright (c) 2024, Alibaba Inc.
+ *
+ *  Author: Wen Gu <guwen@linux.alibaba.com>
+ *          Tony Lu <tonylu@linux.alibaba.com>
+ *
+ */
+
+#ifndef _SMC_LOOPBACK_H
+#define _SMC_LOOPBACK_H
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <net/smc.h>
+
+#if IS_ENABLED(CONFIG_SMC_LO)
+#define SMC_LO_MAX_DMBS                5000
+
+struct smc_lo_dev {
+       struct smcd_dev *smcd;
+       struct device dev;
+};
+
+int smc_loopback_init(void);
+void smc_loopback_exit(void);
+#else
+static inline int smc_loopback_init(void)
+{
+       return 0;
+}
+
+static inline void smc_loopback_exit(void)
+{
+}
+#endif
+
+#endif /* _SMC_LOOPBACK_H */