From 32bf411d2b61110b197dc12095ae922fece64253 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:39 +0100 Subject: [PATCH 01/20] net/smc: Add link counters for IB device ports mainline inclusion from mainline-v5.11-rc1 commit ddc992866f13373e3fd63fd70d9a4452e0d17d69 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=ddc992866f13373e3fd63fd70d9a4452e0d17d69 -------------------------------- Add link counters to the structure of the smc ib device, one counter per ib port. Increase/decrease the counters as needed in the corresponding routines. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_core.c | 13 +++++++++++++ net/smc/smc_ib.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 4bea24ac974f..fe0599873281 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -64,6 +64,16 @@ static inline struct list_head *smc_lgr_list_head(struct smc_link_group *lgr, return &smc_lgr_list.list; } +static void smc_ibdev_cnt_inc(struct smc_link *lnk) +{ + atomic_inc(&lnk->smcibdev->lnk_cnt_by_port[lnk->ibport - 1]); +} + +static void smc_ibdev_cnt_dec(struct smc_link *lnk) +{ + atomic_dec(&lnk->smcibdev->lnk_cnt_by_port[lnk->ibport - 1]); +} + static void smc_lgr_schedule_free_work(struct smc_link_group *lgr) { /* client link group creation always follows the server link group @@ -321,6 +331,7 @@ int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, lnk->link_idx = link_idx; lnk->smcibdev = ini->ib_dev; lnk->ibport = ini->ib_port; + smc_ibdev_cnt_inc(lnk); lnk->path_mtu = ini->ib_dev->pattr[ini->ib_port - 1].active_mtu; atomic_set(&lnk->conn_cnt, 0); smc_llc_link_set_uid(lnk); @@ -364,6 +375,7 @@ int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, clear_llc_lnk: smc_llc_link_clear(lnk, false); out: + smc_ibdev_cnt_dec(lnk); put_device(&ini->ib_dev->ibdev->dev); memset(lnk, 0, sizeof(struct smc_link)); lnk->state = SMC_LNK_UNUSED; @@ -785,6 +797,7 @@ void __smcr_link_clear(struct smc_link *lnk) smc_ib_destroy_queue_pair(lnk); smc_ib_dealloc_protection_domain(lnk); smc_wr_free_link_mem(lnk); + smc_ibdev_cnt_dec(lnk); smc_lgr_put(lnk->lgr); /* lgr_hold in smcr_link_init() */ memset(lnk, 0, sizeof(struct smc_link)); lnk->state = SMC_LNK_UNUSED; diff --git a/net/smc/smc_ib.h b/net/smc/smc_ib.h index d08c58229d4c..260f173f7440 100644 --- a/net/smc/smc_ib.h +++ b/net/smc/smc_ib.h @@ -53,6 +53,8 @@ struct smc_ib_device { /* ib-device infos for smc */ atomic_t lnk_cnt; /* number of links on ibdev */ wait_queue_head_t lnks_deleted; /* wait 4 removal of all links*/ struct mutex mutex; /* protect dev setup+cleanup */ + atomic_t lnk_cnt_by_port[SMC_MAX_PORTS]; + /* number of links per port */ }; struct smc_buf_desc; -- Gitee From 52f8844fa6b4238ca1a2fd0ce688358f8dc0af36 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:40 +0100 Subject: [PATCH 02/20] net/smc: Add diagnostic information to smc ib-device mainline inclusion from mainline-v5.11-rc1 commit 3d453f53c786ac4f1c97022f4bc0e9d7613a05c3 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=3d453f53c786ac4f1c97022f4bc0e9d7613a05c3 -------------------------------- During smc ib-device creation, add network device ifindex to smc ib-device structure. Register for netdevice changes and update ib-device accordingly. This is needed for diagnostic purposes. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_ib.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/smc/smc_ib.h | 2 ++ net/smc/smc_pnet.c | 2 ++ 3 files changed, 48 insertions(+) diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 1413665f3115..e4005f116f4b 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -588,6 +588,49 @@ static void smc_ib_cleanup_per_ibdev(struct smc_ib_device *smcibdev) static struct ib_client smc_ib_client; +static void smc_copy_netdev_ifindex(struct smc_ib_device *smcibdev, int port) +{ + struct ib_device *ibdev = smcibdev->ibdev; + struct net_device *ndev; + + if (!ibdev->ops.get_netdev) + return; + ndev = ibdev->ops.get_netdev(ibdev, port + 1); + if (ndev) { + smcibdev->ndev_ifidx[port] = ndev->ifindex; + dev_put(ndev); + } +} + +void smc_ib_ndev_change(struct net_device *ndev, unsigned long event) +{ + struct smc_ib_device *smcibdev; + struct ib_device *libdev; + struct net_device *lndev; + u8 port_cnt; + int i; + + mutex_lock(&smc_ib_devices.mutex); + list_for_each_entry(smcibdev, &smc_ib_devices.list, list) { + port_cnt = smcibdev->ibdev->phys_port_cnt; + for (i = 0; i < min_t(size_t, port_cnt, SMC_MAX_PORTS); i++) { + libdev = smcibdev->ibdev; + if (!libdev->ops.get_netdev) + continue; + lndev = libdev->ops.get_netdev(libdev, i + 1); + if (lndev) + dev_put(lndev); + if (lndev != ndev) + continue; + if (event == NETDEV_REGISTER) + smcibdev->ndev_ifidx[i] = ndev->ifindex; + if (event == NETDEV_UNREGISTER) + smcibdev->ndev_ifidx[i] = 0; + } + } + mutex_unlock(&smc_ib_devices.mutex); +} + /* callback function for ib_register_client() */ static int smc_ib_add_dev(struct ib_device *ibdev) { @@ -627,6 +670,7 @@ static int smc_ib_add_dev(struct ib_device *ibdev) if (smc_pnetid_by_dev_port(ibdev->dev.parent, i, smcibdev->pnetid[i])) smc_pnetid_by_table_ib(smcibdev, i + 1); + smc_copy_netdev_ifindex(smcibdev, i); pr_warn_ratelimited("smc: ib device %s port %d has pnetid " "%.16s%s\n", smcibdev->ibdev->name, i + 1, diff --git a/net/smc/smc_ib.h b/net/smc/smc_ib.h index 260f173f7440..6ca5e18b0bbd 100644 --- a/net/smc/smc_ib.h +++ b/net/smc/smc_ib.h @@ -55,11 +55,13 @@ struct smc_ib_device { /* ib-device infos for smc */ struct mutex mutex; /* protect dev setup+cleanup */ atomic_t lnk_cnt_by_port[SMC_MAX_PORTS]; /* number of links per port */ + int ndev_ifidx[SMC_MAX_PORTS]; /* ndev if indexes */ }; struct smc_buf_desc; struct smc_link; +void smc_ib_ndev_change(struct net_device *ndev, unsigned long event); int smc_ib_register_client(void) __init; void smc_ib_unregister_client(void); bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport); diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 30bae60d626c..eb0971a1797a 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -828,9 +828,11 @@ static int smc_pnet_netdev_event(struct notifier_block *this, case NETDEV_REBOOT: case NETDEV_UNREGISTER: smc_pnet_remove_by_ndev(event_dev); + smc_ib_ndev_change(event_dev, event); return NOTIFY_OK; case NETDEV_REGISTER: smc_pnet_add_by_ndev(event_dev); + smc_ib_ndev_change(event_dev, event); return NOTIFY_OK; case NETDEV_UP: smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid); -- Gitee From 41c70cca7b4803a6d0e95015b9ead1ac64a03bde Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:41 +0100 Subject: [PATCH 03/20] net/smc: Add diagnostic information to link structure mainline inclusion from mainline-v5.11-rc1 commit 6443b2f60e5754d344bd3a19a0bca9c8fb81737c category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=6443b2f60e5754d344bd3a19a0bca9c8fb81737c -------------------------------- During link creation add net-device ifindex and ib-device name to link structure. This is needed for diagnostic purposes. When diagnostic information is gathered, we need to traverse device, linkgroup and link structures, to be able to do that we need to hold a spinlock for the linkgroup list, without this diagnostic information in link structure, another device list mutex holding would be necessary to dereference the device pointer in the link structure which would be impossible when holding a spinlock already. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_core.c | 10 ++++++++++ net/smc/smc_core.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index fe0599873281..76a86ce94597 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -315,6 +315,15 @@ static u8 smcr_next_link_id(struct smc_link_group *lgr) return link_id; } +static void smcr_copy_dev_info_to_link(struct smc_link *link) +{ + struct smc_ib_device *smcibdev = link->smcibdev; + + snprintf(link->ibname, sizeof(link->ibname), "%s", + smcibdev->ibdev->name); + link->ndev_ifidx = smcibdev->ndev_ifidx[link->ibport - 1]; +} + int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, u8 link_idx, struct smc_init_info *ini) { @@ -332,6 +341,7 @@ int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, lnk->smcibdev = ini->ib_dev; lnk->ibport = ini->ib_port; smc_ibdev_cnt_inc(lnk); + smcr_copy_dev_info_to_link(lnk); lnk->path_mtu = ini->ib_dev->pattr[ini->ib_port - 1].active_mtu; atomic_set(&lnk->conn_cnt, 0); smc_llc_link_set_uid(lnk); diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index ab410fe62fac..4295f26b4443 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -128,6 +128,8 @@ struct smc_link { refcount_t refcnt; /* link reference count */ struct smc_link_group *lgr; /* parent link group */ struct work_struct link_down_wrk; /* wrk to bring link down */ + char ibname[IB_DEVICE_NAME_MAX]; /* ib device name */ + int ndev_ifidx; /* network device ifindex */ enum smc_link_state state; /* state of link */ struct delayed_work llc_testlink_wrk; /* testlink worker */ -- Gitee From 21879b64762fca3ba6dcf459f160d46ef018e55f Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:42 +0100 Subject: [PATCH 04/20] net/smc: Refactor smc ism v2 capability handling mainline inclusion from mainline-v5.11-rc1 commit 49407ae2bc79da1ce29d6ff16c9acb45128b0bf6 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=49407ae2bc79da1ce29d6ff16c9acb45128b0bf6 -------------------------------- Encapsulate the smc ism v2 capability boolean value in a function for better information hiding. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/af_smc.c | 12 ++++++------ net/smc/smc_ism.c | 8 +++++++- net/smc/smc_ism.h | 5 ++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 6a4a19f57a39..7b65eb8ca8bc 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -933,7 +933,7 @@ static int smc_find_proposal_devices(struct smc_sock *smc, ini->smc_type_v1 = SMC_TYPE_N; } /* else RDMA is supported for this connection */ } - if (smc_ism_v2_capable && smc_find_ism_v2_device_clnt(smc, ini)) + if (smc_ism_is_v2_capable() && smc_find_ism_v2_device_clnt(smc, ini)) ini->smc_type_v2 = SMC_TYPE_N; /* if neither ISM nor RDMA are supported, fallback */ @@ -1191,7 +1191,7 @@ static int smc_connect_check_aclc(struct smc_init_info *ini, /* perform steps before actually connecting */ static int __smc_connect(struct smc_sock *smc) { - u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1; + u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1; struct smc_clc_msg_accept_confirm_v2 *aclc2; struct smc_clc_msg_accept_confirm *aclc; struct smc_init_info *ini = NULL; @@ -1216,9 +1216,9 @@ static int __smc_connect(struct smc_sock *smc) version); ini->smcd_version = SMC_V1; - ini->smcd_version |= smc_ism_v2_capable ? SMC_V2 : 0; + ini->smcd_version |= smc_ism_is_v2_capable() ? SMC_V2 : 0; ini->smc_type_v1 = SMC_TYPE_B; - ini->smc_type_v2 = smc_ism_v2_capable ? SMC_TYPE_D : SMC_TYPE_N; + ini->smc_type_v2 = smc_ism_is_v2_capable() ? SMC_TYPE_D : SMC_TYPE_N; /* get vlan id from IP device */ if (smc_vlan_by_tcpsk(smc->clcsock, ini)) { @@ -1683,7 +1683,7 @@ static int smc_listen_v2_check(struct smc_sock *new_smc, if (pclc->hdr.version > SMC_V1) ini->smcd_version |= ini->smc_type_v2 != SMC_TYPE_N ? SMC_V2 : 0; - if (!smc_ism_v2_capable) { + if (!smc_ism_is_v2_capable()) { ini->smcd_version &= ~SMC_V2; goto out; } @@ -2001,7 +2001,7 @@ static void smc_listen_work(struct work_struct *work) { struct smc_sock *new_smc = container_of(work, struct smc_sock, smc_listen_work); - u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1; + u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1; struct socket *newclcsock = new_smc->clcsock; struct smc_clc_msg_accept_confirm *cclc; struct smc_clc_msg_proposal_area *buf; diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index 8e33c0128d73..721d8e79a5d3 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -21,7 +21,7 @@ struct smcd_dev_list smcd_dev_list = { .mutex = __MUTEX_INITIALIZER(smcd_dev_list.mutex) }; -bool smc_ism_v2_capable; +static bool smc_ism_v2_capable; /* Test if an ISM communication is possible - same CPC */ int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd) @@ -51,6 +51,12 @@ u16 smc_ism_get_chid(struct smcd_dev *smcd) return smcd->ops->get_chid(smcd); } +/* HW supports ISM V2 and thus System EID is defined */ +bool smc_ism_is_v2_capable(void) +{ + return smc_ism_v2_capable; +} + /* Set a connection using this DMBE. */ void smc_ism_set_conn(struct smc_connection *conn) { diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h index 8048e09ddcf8..481a4b7df30b 100644 --- a/net/smc/smc_ism.h +++ b/net/smc/smc_ism.h @@ -10,6 +10,7 @@ #define SMCD_ISM_H #include +#include #include #include "smc.h" @@ -20,9 +21,6 @@ struct smcd_dev_list { /* List of SMCD devices */ }; extern struct smcd_dev_list smcd_dev_list; /* list of smcd devices */ -extern bool smc_ism_v2_capable; /* HW supports ISM V2 and thus - * System EID is defined - */ struct smc_ism_vlanid { /* VLAN id set on ISM device */ struct list_head list; @@ -52,5 +50,6 @@ int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos, int smc_ism_signal_shutdown(struct smc_link_group *lgr); void smc_ism_get_system_eid(struct smcd_dev *dev, u8 **eid); u16 smc_ism_get_chid(struct smcd_dev *dev); +bool smc_ism_is_v2_capable(void); void smc_ism_init(void); #endif -- Gitee From 79e8b36d9f88b8ee71129872b8c89a06d767d0c8 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:43 +0100 Subject: [PATCH 05/20] net/smc: Introduce generic netlink interface for diagnostic purposes mainline inclusion from mainline-v5.11-rc1 commit e8372d9d21451a2f2947c2b63b5184f3d4d0bff9 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=e8372d9d21451a2f2947c2b63b5184f3d4d0bff9 -------------------------------- Introduce generic netlink interface infrastructure to expose the diagnostic information regarding smc linkgroups, links and devices. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 11 +++++++++ net/smc/Makefile | 2 +- net/smc/af_smc.c | 10 +++++++- net/smc/smc_netlink.c | 53 ++++++++++++++++++++++++++++++++++++++++ net/smc/smc_netlink.h | 23 +++++++++++++++++ 5 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 net/smc/smc_netlink.c create mode 100644 net/smc/smc_netlink.h diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 0e11ca421ca4..b604d64542e8 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -33,4 +33,15 @@ enum { /* SMC PNET Table commands */ #define SMCR_GENL_FAMILY_NAME "SMC_PNETID" #define SMCR_GENL_FAMILY_VERSION 1 +/* gennetlink interface to access non-socket information from SMC module */ +#define SMC_GENL_FAMILY_NAME "SMC_GEN_NETLINK" +#define SMC_GENL_FAMILY_VERSION 1 + +/* SMC_GENL_FAMILY top level attributes */ +enum { + SMC_GEN_UNSPEC, + __SMC_GEN_MAX, + SMC_GEN_MAX = __SMC_GEN_MAX - 1 +}; + #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/Makefile b/net/smc/Makefile index 79f53cc7d8dc..481a5d072f61 100644 --- a/net/smc/Makefile +++ b/net/smc/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_SMC) += smc.o obj-$(CONFIG_SMC_DIAG) += smc_diag.o 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-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc-$(CONFIG_SYSCTL) += smc_sysctl.o diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 7b65eb8ca8bc..6acb92aa5fc6 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -45,6 +45,7 @@ #include "smc_ib.h" #include "smc_ism.h" #include "smc_pnet.h" +#include "smc_netlink.h" #include "smc_tx.h" #include "smc_rx.h" #include "smc_close.h" @@ -2886,10 +2887,14 @@ static int __init smc_init(void) smc_ism_init(); smc_clc_init(); - rc = smc_pnet_init(); + rc = smc_nl_init(); if (rc) goto out_pernet_subsys; + rc = smc_pnet_init(); + if (rc) + goto out_nl; + rc = -ENOMEM; smc_tcp_ls_wq = alloc_workqueue("smc_tcp_ls_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); @@ -2966,6 +2971,8 @@ static int __init smc_init(void) destroy_workqueue(smc_tcp_ls_wq); out_pnet: smc_pnet_exit(); +out_nl: + smc_nl_exit(); out_pernet_subsys: unregister_pernet_subsys(&smc_net_ops); @@ -2984,6 +2991,7 @@ static void __exit smc_exit(void) proto_unregister(&smc_proto6); proto_unregister(&smc_proto); smc_pnet_exit(); + smc_nl_exit(); unregister_pernet_subsys(&smc_net_ops); rcu_barrier(); } diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c new file mode 100644 index 000000000000..4f964d03b372 --- /dev/null +++ b/net/smc/smc_netlink.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Shared Memory Communications over RDMA (SMC-R) and RoCE + * + * Generic netlink support functions to interact with SMC module + * + * Copyright IBM Corp. 2020 + * + * Author(s): Guvenc Gulce + */ + +#include +#include +#include +#include +#include +#include + +#include "smc_core.h" +#include "smc_netlink.h" + +#define SMC_CMD_MAX_ATTR 1 + +/* SMC_GENL generic netlink operation definition */ +static const struct genl_ops smc_gen_nl_ops[] = { +}; + +static const struct nla_policy smc_gen_nl_policy[2] = { + [SMC_CMD_MAX_ATTR] = { .type = NLA_REJECT, }, +}; + +/* SMC_GENL family definition */ +struct genl_family smc_gen_nl_family __ro_after_init = { + .hdrsize = 0, + .name = SMC_GENL_FAMILY_NAME, + .version = SMC_GENL_FAMILY_VERSION, + .maxattr = SMC_CMD_MAX_ATTR, + .policy = smc_gen_nl_policy, + .netnsok = true, + .module = THIS_MODULE, + .ops = smc_gen_nl_ops, + .n_ops = ARRAY_SIZE(smc_gen_nl_ops) +}; + +int __init smc_nl_init(void) +{ + return genl_register_family(&smc_gen_nl_family); +} + +void smc_nl_exit(void) +{ + genl_unregister_family(&smc_gen_nl_family); +} diff --git a/net/smc/smc_netlink.h b/net/smc/smc_netlink.h new file mode 100644 index 000000000000..0c757232c0d0 --- /dev/null +++ b/net/smc/smc_netlink.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Shared Memory Communications over RDMA (SMC-R) and RoCE + * + * SMC Generic netlink operations + * + * Copyright IBM Corp. 2020 + * + * Author(s): Guvenc Gulce + */ + +#ifndef _SMC_NETLINK_H +#define _SMC_NETLINK_H + +#include +#include + +extern struct genl_family smc_gen_nl_family; + +int smc_nl_init(void) __init; +void smc_nl_exit(void); + +#endif -- Gitee From f0f94c153527db4c8c2cb08d9ea7214d45ce0134 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:44 +0100 Subject: [PATCH 06/20] net/smc: Add support for obtaining system information mainline inclusion from mainline-v5.11-rc1 commit 099b990bd11a3a96b5d59973f482018e5cbde6c3 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=099b990bd11a3a96b5d59973f482018e5cbde6c3 -------------------------------- Add new netlink command to obtain system information of the smc module. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 18 ++++++++++++ net/smc/smc_clc.c | 5 ++++ net/smc/smc_clc.h | 1 + net/smc/smc_core.c | 60 ++++++++++++++++++++++++++++++++++++++++ net/smc/smc_core.h | 2 ++ net/smc/smc_netlink.c | 5 ++++ net/smc/smc_netlink.h | 9 ++++++ 7 files changed, 100 insertions(+) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index b604d64542e8..1b8d4e770be9 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -37,11 +37,29 @@ enum { /* SMC PNET Table commands */ #define SMC_GENL_FAMILY_NAME "SMC_GEN_NETLINK" #define SMC_GENL_FAMILY_VERSION 1 +/* SMC_GENL_FAMILY commands */ +enum { + SMC_NETLINK_GET_SYS_INFO = 1, +}; + /* SMC_GENL_FAMILY top level attributes */ enum { SMC_GEN_UNSPEC, + SMC_GEN_SYS_INFO, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; +/* SMC_GEN_SYS_INFO attributes */ +enum { + SMC_NLA_SYS_UNSPEC, + SMC_NLA_SYS_VER, /* u8 */ + SMC_NLA_SYS_REL, /* u8 */ + SMC_NLA_SYS_IS_ISM_V2, /* u8 */ + SMC_NLA_SYS_LOCAL_HOST, /* string */ + SMC_NLA_SYS_SEID, /* string */ + __SMC_NLA_SYS_MAX, + SMC_NLA_SYS_MAX = __SMC_NLA_SYS_MAX - 1 +}; + #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index c9450ab0e23b..838470f897d0 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -775,6 +775,11 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact, return len > 0 ? 0 : len; } +void smc_clc_get_hostname(u8 **host) +{ + *host = &smc_hostname[0]; +} + void __init smc_clc_init(void) { struct new_utsname *u; diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h index 8992949900e9..49291909ffca 100644 --- a/net/smc/smc_clc.h +++ b/net/smc/smc_clc.h @@ -329,5 +329,6 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact, u8 version); void smc_clc_init(void) __init; +void smc_clc_get_hostname(u8 **host); #endif diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 76a86ce94597..c1b2e135891d 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,7 @@ #include "smc_close.h" #include "smc_ism.h" #include "smc_sysctl.h" +#include "smc_netlink.h" #define SMC_LGR_NUM_INCR 256 #define SMC_LGR_FREE_DELAY_SERV (600 * HZ) @@ -216,6 +219,63 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn) write_unlock_bh(&lgr->conns_lock); } +int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + char hostname[SMC_MAX_HOSTNAME_LEN + 1]; + char smc_seid[SMC_MAX_EID_LEN + 1]; + struct smcd_dev *smcd_dev; + struct nlattr *attrs; + u8 *seid = NULL; + u8 *host = NULL; + void *nlh; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_SYS_INFO); + if (!nlh) + goto errmsg; + if (cb_ctx->pos[0]) + goto errout; + attrs = nla_nest_start(skb, SMC_GEN_SYS_INFO); + if (!attrs) + goto errout; + if (nla_put_u8(skb, SMC_NLA_SYS_VER, SMC_V2)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_SYS_REL, SMC_RELEASE)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_SYS_IS_ISM_V2, smc_ism_is_v2_capable())) + goto errattr; + smc_clc_get_hostname(&host); + if (host) { + snprintf(hostname, sizeof(hostname), "%s", host); + if (nla_put_string(skb, SMC_NLA_SYS_LOCAL_HOST, hostname)) + goto errattr; + } + mutex_lock(&smcd_dev_list.mutex); + smcd_dev = list_first_entry_or_null(&smcd_dev_list.list, + struct smcd_dev, list); + if (smcd_dev) + smc_ism_get_system_eid(smcd_dev, &seid); + mutex_unlock(&smcd_dev_list.mutex); + if (seid && smc_ism_is_v2_capable()) { + snprintf(smc_seid, sizeof(smc_seid), "%s", seid); + if (nla_put_string(skb, SMC_NLA_SYS_SEID, smc_seid)) + goto errattr; + } + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + cb_ctx->pos[0] = 1; + return skb->len; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return skb->len; +} + void smc_lgr_cleanup_early(struct smc_connection *conn) { struct smc_link_group *lgr = conn->lgr; diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 4295f26b4443..1610a96f919b 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -14,6 +14,7 @@ #include #include +#include #include "smc.h" #include "smc_ib.h" @@ -440,6 +441,7 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr, struct smc_link *from_lnk, bool is_dev_err); void smcr_link_down_cond(struct smc_link *lnk); void smcr_link_down_cond_sched(struct smc_link *lnk); +int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb); static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) { diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index 4f964d03b372..ce06d269a54b 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -23,6 +23,11 @@ /* SMC_GENL generic netlink operation definition */ static const struct genl_ops smc_gen_nl_ops[] = { + { + .cmd = SMC_NETLINK_GET_SYS_INFO, + /* can be retrieved by unprivileged users */ + .dumpit = smc_nl_get_sys_info, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { diff --git a/net/smc/smc_netlink.h b/net/smc/smc_netlink.h index 0c757232c0d0..3477265cba6c 100644 --- a/net/smc/smc_netlink.h +++ b/net/smc/smc_netlink.h @@ -17,6 +17,15 @@ extern struct genl_family smc_gen_nl_family; +struct smc_nl_dmp_ctx { + int pos[2]; +}; + +static inline struct smc_nl_dmp_ctx *smc_nl_dmp_ctx(struct netlink_callback *c) +{ + return (struct smc_nl_dmp_ctx *)c->ctx; +} + int smc_nl_init(void) __init; void smc_nl_exit(void); -- Gitee From baef2a028d02f8efc2c46f49d193f4a05c245a97 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:45 +0100 Subject: [PATCH 07/20] net/smc: Introduce SMCR get linkgroup command mainline inclusion from mainline-v5.11-rc1 commit e9b8c845cb342a3ab3d92235a54d0d1ad06d7204 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=e9b8c845cb342a3ab3d92235a54d0d1ad06d7204 -------------------------------- Introduce get linkgroup command which loops through all available SMCR linkgroups. It uses the SMC-R linkgroup list as entry point, not the socket list, which makes linkgroup diagnosis possible, in case linkgroup does not contain active connections anymore. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 15 +++++++ net/smc/smc_core.c | 85 ++++++++++++++++++++++++++++++++++++++++ net/smc/smc_core.h | 1 + net/smc/smc_netlink.c | 5 +++ 4 files changed, 106 insertions(+) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 1b8d4e770be9..3ae8ca4e5256 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -40,12 +40,14 @@ enum { /* SMC PNET Table commands */ /* SMC_GENL_FAMILY commands */ enum { SMC_NETLINK_GET_SYS_INFO = 1, + SMC_NETLINK_GET_LGR_SMCR, }; /* SMC_GENL_FAMILY top level attributes */ enum { SMC_GEN_UNSPEC, SMC_GEN_SYS_INFO, /* nest */ + SMC_GEN_LGR_SMCR, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -62,4 +64,17 @@ enum { SMC_NLA_SYS_MAX = __SMC_NLA_SYS_MAX - 1 }; +/* SMC_GEN_LGR_SMCR attributes */ +enum { + SMC_NLA_LGR_R_UNSPEC, + SMC_NLA_LGR_R_ID, /* u32 */ + SMC_NLA_LGR_R_ROLE, /* u8 */ + SMC_NLA_LGR_R_TYPE, /* u8 */ + SMC_NLA_LGR_R_PNETID, /* string */ + SMC_NLA_LGR_R_VLAN_ID, /* u8 */ + SMC_NLA_LGR_R_CONNS_NUM, /* u32 */ + __SMC_NLA_LGR_R_MAX, + SMC_NLA_LGR_R_MAX = __SMC_NLA_LGR_R_MAX - 1 +}; + #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index c1b2e135891d..8436a1dd1747 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -276,6 +276,91 @@ int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static int smc_nl_fill_lgr(struct smc_link_group *lgr, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + char smc_target[SMC_MAX_PNETID_LEN + 1]; + struct nlattr *attrs; + + attrs = nla_nest_start(skb, SMC_GEN_LGR_SMCR); + if (!attrs) + goto errout; + + if (nla_put_u32(skb, SMC_NLA_LGR_R_ID, *((u32 *)&lgr->id))) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LGR_R_CONNS_NUM, lgr->conns_num)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_R_ROLE, lgr->role)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_R_TYPE, lgr->type)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_R_VLAN_ID, lgr->vlan_id)) + goto errattr; + snprintf(smc_target, sizeof(smc_target), "%s", lgr->pnet_id); + if (nla_put_string(skb, SMC_NLA_LGR_R_PNETID, smc_target)) + goto errattr; + + nla_nest_end(skb, attrs); + return 0; +errattr: + nla_nest_cancel(skb, attrs); +errout: + return -EMSGSIZE; +} + +static int smc_nl_handle_lgr(struct smc_link_group *lgr, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + void *nlh; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_LGR_SMCR); + if (!nlh) + goto errmsg; + if (smc_nl_fill_lgr(lgr, skb, cb)) + goto errout; + + genlmsg_end(skb, nlh); + return 0; + +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + +static void smc_nl_fill_lgr_list(struct smc_lgr_list *smc_lgr, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + struct smc_link_group *lgr; + int snum = cb_ctx->pos[0]; + int num = 0; + + spin_lock_bh(&smc_lgr->lock); + list_for_each_entry(lgr, &smc_lgr->list, list) { + if (num < snum) + goto next; + if (smc_nl_handle_lgr(lgr, skb, cb)) + goto errout; +next: + num++; + } +errout: + spin_unlock_bh(&smc_lgr->lock); + cb_ctx->pos[0] = num; +} + +int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb) +{ + smc_nl_fill_lgr_list(&smc_lgr_list, skb, cb); + return skb->len; +} + void smc_lgr_cleanup_early(struct smc_connection *conn) { struct smc_link_group *lgr = conn->lgr; diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 1610a96f919b..0e0ff10191cf 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -442,6 +442,7 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr, void smcr_link_down_cond(struct smc_link *lnk); void smcr_link_down_cond_sched(struct smc_link *lnk); int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb); +int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb); static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) { diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index ce06d269a54b..490da56c8d3c 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -28,6 +28,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smc_nl_get_sys_info, }, + { + .cmd = SMC_NETLINK_GET_LGR_SMCR, + /* can be retrieved by unprivileged users */ + .dumpit = smcr_nl_get_lgr, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { -- Gitee From 0890020f6d9139ddf4dd0b9272235af5208775af Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:46 +0100 Subject: [PATCH 08/20] net/smc: Introduce SMCR get link command mainline inclusion from mainline-v5.11-rc1 commit 5a7e09d58f3fe2f0d5e8f0da4b1f686491245eb5 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=5a7e09d58f3fe2f0d5e8f0da4b1f686491245eb5 -------------------------------- Introduce get link command which loops through all available links of all available link groups. It uses the SMC-R linkgroup list as entry point, not the socket list, which makes linkgroup diagnosis possible, in case linkgroup does not contain active connections anymore. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 18 ++++++++ net/smc/smc_core.c | 91 ++++++++++++++++++++++++++++++++++++++-- net/smc/smc_core.h | 14 +++++++ net/smc/smc_diag.c | 13 ------ net/smc/smc_netlink.c | 5 +++ 5 files changed, 124 insertions(+), 17 deletions(-) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 3ae8ca4e5256..ed638dbfff08 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -41,6 +41,7 @@ enum { /* SMC PNET Table commands */ enum { SMC_NETLINK_GET_SYS_INFO = 1, SMC_NETLINK_GET_LGR_SMCR, + SMC_NETLINK_GET_LINK_SMCR, }; /* SMC_GENL_FAMILY top level attributes */ @@ -48,6 +49,7 @@ enum { SMC_GEN_UNSPEC, SMC_GEN_SYS_INFO, /* nest */ SMC_GEN_LGR_SMCR, /* nest */ + SMC_GEN_LINK_SMCR, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -77,4 +79,20 @@ enum { SMC_NLA_LGR_R_MAX = __SMC_NLA_LGR_R_MAX - 1 }; +/* SMC_GEN_LINK_SMCR attributes */ +enum { + SMC_NLA_LINK_UNSPEC, + SMC_NLA_LINK_ID, /* u8 */ + SMC_NLA_LINK_IB_DEV, /* string */ + SMC_NLA_LINK_IB_PORT, /* u8 */ + SMC_NLA_LINK_GID, /* string */ + SMC_NLA_LINK_PEER_GID, /* string */ + SMC_NLA_LINK_CONN_CNT, /* u32 */ + SMC_NLA_LINK_NET_DEV, /* u32 */ + SMC_NLA_LINK_UID, /* u32 */ + SMC_NLA_LINK_PEER_UID, /* u32 */ + SMC_NLA_LINK_STATE, /* u32 */ + __SMC_NLA_LINK_MAX, + SMC_NLA_LINK_MAX = __SMC_NLA_LINK_MAX - 1 +}; #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 8436a1dd1747..efbaf0b12e97 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -309,11 +309,74 @@ static int smc_nl_fill_lgr(struct smc_link_group *lgr, return -EMSGSIZE; } +static int smc_nl_fill_lgr_link(struct smc_link_group *lgr, + struct smc_link *link, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + char smc_ibname[IB_DEVICE_NAME_MAX + 1]; + u8 smc_gid_target[41]; + struct nlattr *attrs; + u32 link_uid = 0; + void *nlh; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_LINK_SMCR); + if (!nlh) + goto errmsg; + + attrs = nla_nest_start(skb, SMC_GEN_LINK_SMCR); + if (!attrs) + goto errout; + + if (nla_put_u8(skb, SMC_NLA_LINK_ID, link->link_id)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LINK_STATE, link->state)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LINK_CONN_CNT, + atomic_read(&link->conn_cnt))) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LINK_IB_PORT, link->ibport)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LINK_NET_DEV, link->ndev_ifidx)) + goto errattr; + snprintf(smc_ibname, sizeof(smc_ibname), "%s", link->ibname); + if (nla_put_string(skb, SMC_NLA_LINK_IB_DEV, smc_ibname)) + goto errattr; + memcpy(&link_uid, link->link_uid, sizeof(link_uid)); + if (nla_put_u32(skb, SMC_NLA_LINK_UID, link_uid)) + goto errattr; + memcpy(&link_uid, link->peer_link_uid, sizeof(link_uid)); + if (nla_put_u32(skb, SMC_NLA_LINK_PEER_UID, link_uid)) + goto errattr; + memset(smc_gid_target, 0, sizeof(smc_gid_target)); + smc_gid_be16_convert(smc_gid_target, link->gid); + if (nla_put_string(skb, SMC_NLA_LINK_GID, smc_gid_target)) + goto errattr; + memset(smc_gid_target, 0, sizeof(smc_gid_target)); + smc_gid_be16_convert(smc_gid_target, link->peer_gid); + if (nla_put_string(skb, SMC_NLA_LINK_PEER_GID, smc_gid_target)) + goto errattr; + + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + return 0; +errattr: + nla_nest_cancel(skb, attrs); +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + static int smc_nl_handle_lgr(struct smc_link_group *lgr, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, + bool list_links) { void *nlh; + int i; nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &smc_gen_nl_family, NLM_F_MULTI, @@ -324,6 +387,15 @@ static int smc_nl_handle_lgr(struct smc_link_group *lgr, goto errout; genlmsg_end(skb, nlh); + if (!list_links) + goto out; + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { + if (!smc_link_usable(&lgr->lnk[i])) + continue; + if (smc_nl_fill_lgr_link(lgr, &lgr->lnk[i], skb, cb)) + goto errout; + } +out: return 0; errout: @@ -334,7 +406,8 @@ static int smc_nl_handle_lgr(struct smc_link_group *lgr, static void smc_nl_fill_lgr_list(struct smc_lgr_list *smc_lgr, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, + bool list_links) { struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); struct smc_link_group *lgr; @@ -345,7 +418,7 @@ static void smc_nl_fill_lgr_list(struct smc_lgr_list *smc_lgr, list_for_each_entry(lgr, &smc_lgr->list, list) { if (num < snum) goto next; - if (smc_nl_handle_lgr(lgr, skb, cb)) + if (smc_nl_handle_lgr(lgr, skb, cb, list_links)) goto errout; next: num++; @@ -357,7 +430,17 @@ static void smc_nl_fill_lgr_list(struct smc_lgr_list *smc_lgr, int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb) { - smc_nl_fill_lgr_list(&smc_lgr_list, skb, cb); + bool list_links = false; + + smc_nl_fill_lgr_list(&smc_lgr_list, skb, cb, list_links); + return skb->len; +} + +int smcr_nl_get_link(struct sk_buff *skb, struct netlink_callback *cb) +{ + bool list_links = true; + + smc_nl_fill_lgr_list(&smc_lgr_list, skb, cb, list_links); return skb->len; } diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 0e0ff10191cf..b6884101dbe6 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -390,6 +390,19 @@ static inline bool smc_link_active(struct smc_link *lnk) return lnk->state == SMC_LNK_ACTIVE; } +static inline void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw) +{ + sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", + be16_to_cpu(((__be16 *)gid_raw)[0]), + be16_to_cpu(((__be16 *)gid_raw)[1]), + be16_to_cpu(((__be16 *)gid_raw)[2]), + be16_to_cpu(((__be16 *)gid_raw)[3]), + be16_to_cpu(((__be16 *)gid_raw)[4]), + be16_to_cpu(((__be16 *)gid_raw)[5]), + be16_to_cpu(((__be16 *)gid_raw)[6]), + be16_to_cpu(((__be16 *)gid_raw)[7])); +} + struct smc_sock; struct smc_clc_msg_accept_confirm; struct smc_clc_msg_local; @@ -443,6 +456,7 @@ void smcr_link_down_cond(struct smc_link *lnk); void smcr_link_down_cond_sched(struct smc_link *lnk); int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb); int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb); +int smcr_nl_get_link(struct sk_buff *skb, struct netlink_callback *cb); static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) { diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c index f15fca59b4b2..4dd4f9e694da 100644 --- a/net/smc/smc_diag.c +++ b/net/smc/smc_diag.c @@ -31,19 +31,6 @@ static struct smc_diag_dump_ctx *smc_dump_context(struct netlink_callback *cb) return (struct smc_diag_dump_ctx *)cb->ctx; } -static void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw) -{ - sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", - be16_to_cpu(((__be16 *)gid_raw)[0]), - be16_to_cpu(((__be16 *)gid_raw)[1]), - be16_to_cpu(((__be16 *)gid_raw)[2]), - be16_to_cpu(((__be16 *)gid_raw)[3]), - be16_to_cpu(((__be16 *)gid_raw)[4]), - be16_to_cpu(((__be16 *)gid_raw)[5]), - be16_to_cpu(((__be16 *)gid_raw)[6]), - be16_to_cpu(((__be16 *)gid_raw)[7])); -} - static void smc_diag_msg_common_fill(struct smc_diag_msg *r, struct sock *sk) { struct smc_sock *smc = smc_sk(sk); diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index 490da56c8d3c..a41f78f488a2 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -33,6 +33,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smcr_nl_get_lgr, }, + { + .cmd = SMC_NETLINK_GET_LINK_SMCR, + /* can be retrieved by unprivileged users */ + .dumpit = smcr_nl_get_link, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { -- Gitee From 116a1cfbea2219b65cd474a52f28c67116f977c2 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:47 +0100 Subject: [PATCH 09/20] net/smc: Add SMC-D Linkgroup diagnostic support mainline inclusion from mainline-v5.11-rc1 commit 8f9dde4bf230f5c54a24c42a989dd9d88ec95695 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=8f9dde4bf230f5c54a24c42a989dd9d88ec95695 -------------------------------- Deliver SMCD Linkgroup information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 27 ++++++++ net/smc/smc_core.c | 130 +++++++++++++++++++++++++++++++++++++++ net/smc/smc_core.h | 1 + net/smc/smc_netlink.c | 5 ++ 4 files changed, 163 insertions(+) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index ed638dbfff08..707e8af4f0c8 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -42,6 +42,7 @@ enum { SMC_NETLINK_GET_SYS_INFO = 1, SMC_NETLINK_GET_LGR_SMCR, SMC_NETLINK_GET_LINK_SMCR, + SMC_NETLINK_GET_LGR_SMCD, }; /* SMC_GENL_FAMILY top level attributes */ @@ -50,6 +51,7 @@ enum { SMC_GEN_SYS_INFO, /* nest */ SMC_GEN_LGR_SMCR, /* nest */ SMC_GEN_LINK_SMCR, /* nest */ + SMC_GEN_LGR_SMCD, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -66,6 +68,15 @@ enum { SMC_NLA_SYS_MAX = __SMC_NLA_SYS_MAX - 1 }; +/* SMC_NLA_LGR_V2 nested attributes */ +enum { + SMC_NLA_LGR_V2_VER, /* u8 */ + SMC_NLA_LGR_V2_REL, /* u8 */ + SMC_NLA_LGR_V2_OS, /* u8 */ + SMC_NLA_LGR_V2_NEG_EID, /* string */ + SMC_NLA_LGR_V2_PEER_HOST, /* string */ +}; + /* SMC_GEN_LGR_SMCR attributes */ enum { SMC_NLA_LGR_R_UNSPEC, @@ -95,4 +106,20 @@ enum { __SMC_NLA_LINK_MAX, SMC_NLA_LINK_MAX = __SMC_NLA_LINK_MAX - 1 }; + +/* SMC_GEN_LGR_SMCD attributes */ +enum { + SMC_NLA_LGR_D_UNSPEC, + SMC_NLA_LGR_D_ID, /* u32 */ + SMC_NLA_LGR_D_GID, /* u64 */ + SMC_NLA_LGR_D_PEER_GID, /* u64 */ + SMC_NLA_LGR_D_VLAN_ID, /* u8 */ + SMC_NLA_LGR_D_CONNS_NUM, /* u32 */ + SMC_NLA_LGR_D_PNETID, /* string */ + SMC_NLA_LGR_D_CHID, /* u16 */ + SMC_NLA_LGR_D_PAD, /* flag */ + SMC_NLA_LGR_V2, /* nest */ + __SMC_NLA_LGR_D_MAX, + SMC_NLA_LGR_D_MAX = __SMC_NLA_LGR_D_MAX - 1 +}; #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index efbaf0b12e97..770170e808b7 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -428,6 +428,130 @@ static void smc_nl_fill_lgr_list(struct smc_lgr_list *smc_lgr, cb_ctx->pos[0] = num; } +static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + char smc_host[SMC_MAX_HOSTNAME_LEN + 1]; + char smc_pnet[SMC_MAX_PNETID_LEN + 1]; + char smc_eid[SMC_MAX_EID_LEN + 1]; + struct nlattr *v2_attrs; + struct nlattr *attrs; + void *nlh; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_LGR_SMCD); + if (!nlh) + goto errmsg; + + attrs = nla_nest_start(skb, SMC_GEN_LGR_SMCD); + if (!attrs) + goto errout; + + if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id))) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID, lgr->smcd->local_gid, + SMC_NLA_LGR_D_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid, + SMC_NLA_LGR_D_PAD)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LGR_D_CONNS_NUM, lgr->conns_num)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_LGR_D_CHID, smc_ism_get_chid(lgr->smcd))) + goto errattr; + snprintf(smc_pnet, sizeof(smc_pnet), "%s", lgr->smcd->pnetid); + if (nla_put_string(skb, SMC_NLA_LGR_D_PNETID, smc_pnet)) + goto errattr; + + v2_attrs = nla_nest_start(skb, SMC_NLA_LGR_V2); + if (!v2_attrs) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_V2_VER, lgr->smc_version)) + goto errv2attr; + if (nla_put_u8(skb, SMC_NLA_LGR_V2_REL, lgr->peer_smc_release)) + goto errv2attr; + if (nla_put_u8(skb, SMC_NLA_LGR_V2_OS, lgr->peer_os)) + goto errv2attr; + snprintf(smc_host, sizeof(smc_host), "%s", lgr->peer_hostname); + if (nla_put_string(skb, SMC_NLA_LGR_V2_PEER_HOST, smc_host)) + goto errv2attr; + snprintf(smc_eid, sizeof(smc_eid), "%s", lgr->negotiated_eid); + if (nla_put_string(skb, SMC_NLA_LGR_V2_NEG_EID, smc_eid)) + goto errv2attr; + + nla_nest_end(skb, v2_attrs); + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + return 0; + +errv2attr: + nla_nest_cancel(skb, v2_attrs); +errattr: + nla_nest_cancel(skb, attrs); +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + +static int smc_nl_handle_smcd_lgr(struct smcd_dev *dev, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + struct smc_link_group *lgr; + int snum = cb_ctx->pos[1]; + int rc = 0, num = 0; + + spin_lock_bh(&dev->lgr_lock); + list_for_each_entry(lgr, &dev->lgr_list, list) { + if (!lgr->is_smcd) + continue; + if (num < snum) + goto next; + rc = smc_nl_fill_smcd_lgr(lgr, skb, cb); + if (rc) + goto errout; +next: + num++; + } +errout: + spin_unlock_bh(&dev->lgr_lock); + cb_ctx->pos[1] = num; + return rc; +} + +static int smc_nl_fill_smcd_dev(struct smcd_dev_list *dev_list, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + struct smcd_dev *smcd_dev; + int snum = cb_ctx->pos[0]; + int rc = 0, num = 0; + + mutex_lock(&dev_list->mutex); + list_for_each_entry(smcd_dev, &dev_list->list, list) { + if (list_empty(&smcd_dev->lgr_list)) + continue; + if (num < snum) + goto next; + rc = smc_nl_handle_smcd_lgr(smcd_dev, skb, cb); + if (rc) + goto errout; +next: + num++; + } +errout: + mutex_unlock(&dev_list->mutex); + cb_ctx->pos[0] = num; + return rc; +} + int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb) { bool list_links = false; @@ -444,6 +568,12 @@ int smcr_nl_get_link(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +int smcd_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb) +{ + smc_nl_fill_smcd_dev(&smcd_dev_list, skb, cb); + return skb->len; +} + void smc_lgr_cleanup_early(struct smc_connection *conn) { struct smc_link_group *lgr = conn->lgr; diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index b6884101dbe6..f68240c1d982 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -457,6 +457,7 @@ void smcr_link_down_cond_sched(struct smc_link *lnk); int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb); int smcr_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb); int smcr_nl_get_link(struct sk_buff *skb, struct netlink_callback *cb); +int smcd_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb); static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) { diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index a41f78f488a2..95bce936534f 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -38,6 +38,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smcr_nl_get_link, }, + { + .cmd = SMC_NETLINK_GET_LGR_SMCD, + /* can be retrieved by unprivileged users */ + .dumpit = smcd_nl_get_lgr, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { -- Gitee From 2c48879181107c19f9589e52a4cdb92b358f15fa Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:48 +0100 Subject: [PATCH 10/20] net/smc: Add support for obtaining SMCD device list mainline inclusion from mainline-v5.11-rc1 commit aaf95523d5824ebc2c8c185a2de51063a750c446 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=aaf95523d5824ebc2c8c185a2de51063a750c446 -------------------------------- Deliver SMCD device information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 28 +++++++++++++ net/smc/smc_core.h | 28 +++++++++++++ net/smc/smc_ism.c | 91 ++++++++++++++++++++++++++++++++++++++++ net/smc/smc_ism.h | 1 + net/smc/smc_netlink.c | 6 +++ 5 files changed, 154 insertions(+) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 707e8af4f0c8..3cb40ab049d9 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -37,12 +37,15 @@ enum { /* SMC PNET Table commands */ #define SMC_GENL_FAMILY_NAME "SMC_GEN_NETLINK" #define SMC_GENL_FAMILY_VERSION 1 +#define SMC_PCI_ID_STR_LEN 16 /* Max length of pci id string */ + /* SMC_GENL_FAMILY commands */ enum { SMC_NETLINK_GET_SYS_INFO = 1, SMC_NETLINK_GET_LGR_SMCR, SMC_NETLINK_GET_LINK_SMCR, SMC_NETLINK_GET_LGR_SMCD, + SMC_NETLINK_GET_DEV_SMCD, }; /* SMC_GENL_FAMILY top level attributes */ @@ -52,6 +55,7 @@ enum { SMC_GEN_LGR_SMCR, /* nest */ SMC_GEN_LINK_SMCR, /* nest */ SMC_GEN_LGR_SMCD, /* nest */ + SMC_GEN_DEV_SMCD, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -122,4 +126,28 @@ enum { __SMC_NLA_LGR_D_MAX, SMC_NLA_LGR_D_MAX = __SMC_NLA_LGR_D_MAX - 1 }; + +/* SMC_NLA_DEV_PORT attributes */ +enum { + SMC_NLA_DEV_PORT_UNSPEC, + SMC_NLA_DEV_PORT_PNET_USR, /* u8 */ + SMC_NLA_DEV_PORT_PNETID, /* string */ + __SMC_NLA_DEV_PORT_MAX, + SMC_NLA_DEV_PORT_MAX = __SMC_NLA_DEV_PORT_MAX - 1 +}; + +/* SMC_GEN_DEV_SMCD attributes */ +enum { + SMC_NLA_DEV_UNSPEC, + SMC_NLA_DEV_USE_CNT, /* u32 */ + SMC_NLA_DEV_IS_CRIT, /* u8 */ + SMC_NLA_DEV_PCI_FID, /* u32 */ + SMC_NLA_DEV_PCI_CHID, /* u16 */ + SMC_NLA_DEV_PCI_VENDOR, /* u16 */ + SMC_NLA_DEV_PCI_DEVICE, /* u16 */ + SMC_NLA_DEV_PCI_ID, /* string */ + SMC_NLA_DEV_PORT, /* nest */ + __SMC_NLA_DEV_MAX, + SMC_NLA_DEV_MAX = __SMC_NLA_DEV_MAX - 1 +}; #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index f68240c1d982..739ead4360b0 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -13,6 +13,8 @@ #define _SMC_CORE_H #include +#include +#include #include #include @@ -403,6 +405,32 @@ static inline void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw) be16_to_cpu(((__be16 *)gid_raw)[7])); } +struct smc_pci_dev { + __u32 pci_fid; + __u16 pci_pchid; + __u16 pci_vendor; + __u16 pci_device; + __u8 pci_id[SMC_PCI_ID_STR_LEN]; +}; + +static inline void smc_set_pci_values(struct pci_dev *pci_dev, + struct smc_pci_dev *smc_dev) +{ + smc_dev->pci_vendor = pci_dev->vendor; + smc_dev->pci_device = pci_dev->device; + snprintf(smc_dev->pci_id, sizeof(smc_dev->pci_id), "%s", + pci_name(pci_dev)); +#if IS_ENABLED(CONFIG_S390) + { /* Set s390 specific PCI information */ + struct zpci_dev *zdev; + + zdev = to_zpci(pci_dev); + smc_dev->pci_fid = zdev->fid; + smc_dev->pci_pchid = zdev->pchid; + } +#endif +} + struct smc_sock; struct smc_clc_msg_accept_confirm; struct smc_clc_msg_local; diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index 721d8e79a5d3..de34f57a6ede 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -15,6 +15,7 @@ #include "smc_core.h" #include "smc_ism.h" #include "smc_pnet.h" +#include "smc_netlink.h" struct smcd_dev_list smcd_dev_list = { .list = LIST_HEAD_INIT(smcd_dev_list.list), @@ -207,6 +208,96 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, return rc; } +static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + char smc_pnet[SMC_MAX_PNETID_LEN + 1]; + struct smc_pci_dev smc_pci_dev; + struct nlattr *port_attrs; + struct nlattr *attrs; + int use_cnt = 0; + void *nlh; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_DEV_SMCD); + if (!nlh) + goto errmsg; + attrs = nla_nest_start(skb, SMC_GEN_DEV_SMCD); + if (!attrs) + goto errout; + use_cnt = atomic_read(&smcd->lgr_cnt); + if (nla_put_u32(skb, SMC_NLA_DEV_USE_CNT, use_cnt)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0)) + goto errattr; + memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); + smc_set_pci_values(to_pci_dev(smcd->dev.parent), &smc_pci_dev); + if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_VENDOR, smc_pci_dev.pci_vendor)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_DEVICE, smc_pci_dev.pci_device)) + goto errattr; + if (nla_put_string(skb, SMC_NLA_DEV_PCI_ID, smc_pci_dev.pci_id)) + goto errattr; + + port_attrs = nla_nest_start(skb, SMC_NLA_DEV_PORT); + if (!port_attrs) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_DEV_PORT_PNET_USR, smcd->pnetid_by_user)) + goto errportattr; + snprintf(smc_pnet, sizeof(smc_pnet), "%s", smcd->pnetid); + if (nla_put_string(skb, SMC_NLA_DEV_PORT_PNETID, smc_pnet)) + goto errportattr; + + nla_nest_end(skb, port_attrs); + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + return 0; + +errportattr: + nla_nest_cancel(skb, port_attrs); +errattr: + nla_nest_cancel(skb, attrs); +errout: + nlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + +static void smc_nl_prep_smcd_dev(struct smcd_dev_list *dev_list, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + int snum = cb_ctx->pos[0]; + struct smcd_dev *smcd; + int num = 0; + + mutex_lock(&dev_list->mutex); + list_for_each_entry(smcd, &dev_list->list, list) { + if (num < snum) + goto next; + if (smc_nl_handle_smcd_dev(smcd, skb, cb)) + goto errout; +next: + num++; + } +errout: + mutex_unlock(&dev_list->mutex); + cb_ctx->pos[0] = num; +} + +int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb) +{ + smc_nl_prep_smcd_dev(&smcd_dev_list, skb, cb); + return skb->len; +} + struct smc_ism_event_work { struct work_struct work; struct smcd_dev *smcd; diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h index 481a4b7df30b..113efc7352ed 100644 --- a/net/smc/smc_ism.h +++ b/net/smc/smc_ism.h @@ -52,4 +52,5 @@ void smc_ism_get_system_eid(struct smcd_dev *dev, u8 **eid); u16 smc_ism_get_chid(struct smcd_dev *dev); bool smc_ism_is_v2_capable(void); void smc_ism_init(void); +int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb); #endif diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index 95bce936534f..debdeec53728 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -17,6 +17,7 @@ #include #include "smc_core.h" +#include "smc_ism.h" #include "smc_netlink.h" #define SMC_CMD_MAX_ATTR 1 @@ -43,6 +44,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smcd_nl_get_lgr, }, + { + .cmd = SMC_NETLINK_GET_DEV_SMCD, + /* can be retrieved by unprivileged users */ + .dumpit = smcd_nl_get_device, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { -- Gitee From 867e8aa40386468138f72760c52e0aa5d146aa53 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:49 +0100 Subject: [PATCH 11/20] net/smc: Add support for obtaining SMCR device list mainline inclusion from mainline-v5.11-rc1 commit a3db10efcc4cc9c03a6375920179ade75ea2df7a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=a3db10efcc4cc9c03a6375920179ade75ea2df7a -------------------------------- Deliver SMCR device information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 13 +++- net/smc/smc_core.c | 2 +- net/smc/smc_ib.c | 156 +++++++++++++++++++++++++++++++++++++++ net/smc/smc_ib.h | 2 + net/smc/smc_netlink.c | 6 ++ 5 files changed, 176 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 3cb40ab049d9..3e68da07fba2 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -46,6 +46,7 @@ enum { SMC_NETLINK_GET_LINK_SMCR, SMC_NETLINK_GET_LGR_SMCD, SMC_NETLINK_GET_DEV_SMCD, + SMC_NETLINK_GET_DEV_SMCR, }; /* SMC_GENL_FAMILY top level attributes */ @@ -56,6 +57,7 @@ enum { SMC_GEN_LINK_SMCR, /* nest */ SMC_GEN_LGR_SMCD, /* nest */ SMC_GEN_DEV_SMCD, /* nest */ + SMC_GEN_DEV_SMCR, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -127,16 +129,20 @@ enum { SMC_NLA_LGR_D_MAX = __SMC_NLA_LGR_D_MAX - 1 }; -/* SMC_NLA_DEV_PORT attributes */ +/* SMC_NLA_DEV_PORT nested attributes */ enum { SMC_NLA_DEV_PORT_UNSPEC, SMC_NLA_DEV_PORT_PNET_USR, /* u8 */ SMC_NLA_DEV_PORT_PNETID, /* string */ + SMC_NLA_DEV_PORT_NETDEV, /* u32 */ + SMC_NLA_DEV_PORT_STATE, /* u8 */ + SMC_NLA_DEV_PORT_VALID, /* u8 */ + SMC_NLA_DEV_PORT_LNK_CNT, /* u32 */ __SMC_NLA_DEV_PORT_MAX, SMC_NLA_DEV_PORT_MAX = __SMC_NLA_DEV_PORT_MAX - 1 }; -/* SMC_GEN_DEV_SMCD attributes */ +/* SMC_GEN_DEV_SMCD and SMC_GEN_DEV_SMCR attributes */ enum { SMC_NLA_DEV_UNSPEC, SMC_NLA_DEV_USE_CNT, /* u32 */ @@ -147,7 +153,10 @@ enum { SMC_NLA_DEV_PCI_DEVICE, /* u16 */ SMC_NLA_DEV_PCI_ID, /* string */ SMC_NLA_DEV_PORT, /* nest */ + SMC_NLA_DEV_PORT2, /* nest */ + SMC_NLA_DEV_IB_NAME, /* string */ __SMC_NLA_DEV_MAX, SMC_NLA_DEV_MAX = __SMC_NLA_DEV_MAX - 1 }; + #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 770170e808b7..f7ad52db6fcf 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -39,7 +39,7 @@ #define SMC_LGR_FREE_DELAY_SERV (600 * HZ) #define SMC_LGR_FREE_DELAY_CLNT (SMC_LGR_FREE_DELAY_SERV + 10 * HZ) -static struct smc_lgr_list smc_lgr_list = { /* established link groups */ +struct smc_lgr_list smc_lgr_list = { /* established link groups */ .lock = __SPIN_LOCK_UNLOCKED(smc_lgr_list.lock), .list = LIST_HEAD_INIT(smc_lgr_list.list), .num = 0, diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index e4005f116f4b..6d4912d4179c 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -25,6 +25,7 @@ #include "smc_core.h" #include "smc_wr.h" #include "smc.h" +#include "smc_netlink.h" #define SMC_MAX_CQE 32766 /* max. # of completion queue elements */ @@ -326,6 +327,161 @@ int smc_ib_create_protection_domain(struct smc_link *lnk) return rc; } +static bool smcr_diag_is_dev_critical(struct smc_lgr_list *smc_lgr, + struct smc_ib_device *smcibdev) +{ + struct smc_link_group *lgr; + bool rc = false; + int i; + + spin_lock_bh(&smc_lgr->lock); + list_for_each_entry(lgr, &smc_lgr->list, list) { + if (lgr->is_smcd) + continue; + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { + if (lgr->lnk[i].state == SMC_LNK_UNUSED || + lgr->lnk[i].smcibdev != smcibdev) + continue; + if (lgr->type == SMC_LGR_SINGLE || + lgr->type == SMC_LGR_ASYMMETRIC_LOCAL) { + rc = true; + goto out; + } + } + } +out: + spin_unlock_bh(&smc_lgr->lock); + return rc; +} + +static int smc_nl_handle_dev_port(struct sk_buff *skb, + struct ib_device *ibdev, + struct smc_ib_device *smcibdev, + int port) +{ + char smc_pnet[SMC_MAX_PNETID_LEN + 1]; + struct nlattr *port_attrs; + unsigned char port_state; + int lnk_count = 0; + + port_attrs = nla_nest_start(skb, SMC_NLA_DEV_PORT + port); + if (!port_attrs) + goto errout; + + if (nla_put_u8(skb, SMC_NLA_DEV_PORT_PNET_USR, + smcibdev->pnetid_by_user[port])) + goto errattr; + snprintf(smc_pnet, sizeof(smc_pnet), "%s", + (char *)&smcibdev->pnetid[port]); + if (nla_put_string(skb, SMC_NLA_DEV_PORT_PNETID, smc_pnet)) + goto errattr; + if (nla_put_u32(skb, SMC_NLA_DEV_PORT_NETDEV, + smcibdev->ndev_ifidx[port])) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_DEV_PORT_VALID, 1)) + goto errattr; + port_state = smc_ib_port_active(smcibdev, port + 1); + if (nla_put_u8(skb, SMC_NLA_DEV_PORT_STATE, port_state)) + goto errattr; + lnk_count = atomic_read(&smcibdev->lnk_cnt_by_port[port]); + if (nla_put_u32(skb, SMC_NLA_DEV_PORT_LNK_CNT, lnk_count)) + goto errattr; + nla_nest_end(skb, port_attrs); + return 0; +errattr: + nla_nest_cancel(skb, port_attrs); +errout: + return -EMSGSIZE; +} + +static int smc_nl_handle_smcr_dev(struct smc_ib_device *smcibdev, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + char smc_ibname[IB_DEVICE_NAME_MAX + 1]; + struct smc_pci_dev smc_pci_dev; + struct pci_dev *pci_dev; + unsigned char is_crit; + struct nlattr *attrs; + void *nlh; + int i; + + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_DEV_SMCR); + if (!nlh) + goto errmsg; + attrs = nla_nest_start(skb, SMC_GEN_DEV_SMCR); + if (!attrs) + goto errout; + is_crit = smcr_diag_is_dev_critical(&smc_lgr_list, smcibdev); + if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, is_crit)) + goto errattr; + memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); + pci_dev = to_pci_dev(smcibdev->ibdev->dev.parent); + smc_set_pci_values(pci_dev, &smc_pci_dev); + if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_VENDOR, smc_pci_dev.pci_vendor)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_DEVICE, smc_pci_dev.pci_device)) + goto errattr; + if (nla_put_string(skb, SMC_NLA_DEV_PCI_ID, smc_pci_dev.pci_id)) + goto errattr; + snprintf(smc_ibname, sizeof(smc_ibname), "%s", smcibdev->ibdev->name); + if (nla_put_string(skb, SMC_NLA_DEV_IB_NAME, smc_ibname)) + goto errattr; + for (i = 1; i <= SMC_MAX_PORTS; i++) { + if (!rdma_is_port_valid(smcibdev->ibdev, i)) + continue; + if (smc_nl_handle_dev_port(skb, smcibdev->ibdev, + smcibdev, i - 1)) + goto errattr; + } + + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + return 0; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + +static void smc_nl_prep_smcr_dev(struct smc_ib_devices *dev_list, + struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + struct smc_ib_device *smcibdev; + int snum = cb_ctx->pos[0]; + int num = 0; + + mutex_lock(&dev_list->mutex); + list_for_each_entry(smcibdev, &dev_list->list, list) { + if (num < snum) + goto next; + if (smc_nl_handle_smcr_dev(smcibdev, skb, cb)) + goto errout; +next: + num++; + } +errout: + mutex_unlock(&dev_list->mutex); + cb_ctx->pos[0] = num; +} + +int smcr_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb) +{ + smc_nl_prep_smcr_dev(&smc_ib_devices, skb, cb); + return skb->len; +} + static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) { struct smc_link *lnk = (struct smc_link *)priv; diff --git a/net/smc/smc_ib.h b/net/smc/smc_ib.h index 6ca5e18b0bbd..ead57976d354 100644 --- a/net/smc/smc_ib.h +++ b/net/smc/smc_ib.h @@ -30,6 +30,7 @@ struct smc_ib_devices { /* list of smc ib devices definition */ }; extern struct smc_ib_devices smc_ib_devices; /* list of smc ib devices */ +extern struct smc_lgr_list smc_lgr_list; /* list of linkgroups */ struct smc_ib_device { /* ib-device infos for smc */ struct list_head list; @@ -94,4 +95,5 @@ void smc_ib_sync_sg_for_device(struct smc_link *lnk, int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport, unsigned short vlan_id, u8 gid[], u8 *sgid_index); bool smc_ib_is_valid_local_systemid(void); +int smcr_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb); #endif diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index debdeec53728..140419a19dbf 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -18,6 +18,7 @@ #include "smc_core.h" #include "smc_ism.h" +#include "smc_ib.h" #include "smc_netlink.h" #define SMC_CMD_MAX_ATTR 1 @@ -49,6 +50,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smcd_nl_get_device, }, + { + .cmd = SMC_NETLINK_GET_DEV_SMCR, + /* can be retrieved by unprivileged users */ + .dumpit = smcr_nl_get_device, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { -- Gitee From 0d3d08fe9589b4a22a3222a489c7e27b836ef251 Mon Sep 17 00:00:00 2001 From: Karsten Graul Date: Tue, 15 Dec 2020 10:10:58 +0100 Subject: [PATCH 12/20] net/smc: fix access to parent of an ib device mainline inclusion from mainline-v5.11-rc1 commit 995433b795cec0a4ef6c8603e7642903c621943a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=995433b795cec0a4ef6c8603e7642903c621943a -------------------------------- The parent of an ib device is used to retrieve the PCI device attributes. It turns out that there are possible cases when an ib device has no parent set in the device structure, which may lead to page faults when trying to access this memory. Fix that by checking the parent pointer and consolidate the pci device specific processing in a new function. Fixes: a3db10efcc4c ("net/smc: Add support for obtaining SMCR device list") Reported-by: syzbot+600fef7c414ee7e2d71b@syzkaller.appspotmail.com Signed-off-by: Karsten Graul Link: https://lore.kernel.org/r/20201215091058.49354-2-kgraul@linux.ibm.com Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_ib.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 6d4912d4179c..075cc3cbf636 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -394,6 +394,22 @@ static int smc_nl_handle_dev_port(struct sk_buff *skb, return -EMSGSIZE; } +static bool smc_nl_handle_pci_values(const struct smc_pci_dev *smc_pci_dev, + struct sk_buff *skb) +{ + if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev->pci_fid)) + return false; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev->pci_pchid)) + return false; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_VENDOR, smc_pci_dev->pci_vendor)) + return false; + if (nla_put_u16(skb, SMC_NLA_DEV_PCI_DEVICE, smc_pci_dev->pci_device)) + return false; + if (nla_put_string(skb, SMC_NLA_DEV_PCI_ID, smc_pci_dev->pci_id)) + return false; + return true; +} + static int smc_nl_handle_smcr_dev(struct smc_ib_device *smcibdev, struct sk_buff *skb, struct netlink_callback *cb) @@ -417,19 +433,13 @@ static int smc_nl_handle_smcr_dev(struct smc_ib_device *smcibdev, is_crit = smcr_diag_is_dev_critical(&smc_lgr_list, smcibdev); if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, is_crit)) goto errattr; - memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); - pci_dev = to_pci_dev(smcibdev->ibdev->dev.parent); - smc_set_pci_values(pci_dev, &smc_pci_dev); - if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) - goto errattr; - if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) - goto errattr; - if (nla_put_u16(skb, SMC_NLA_DEV_PCI_VENDOR, smc_pci_dev.pci_vendor)) - goto errattr; - if (nla_put_u16(skb, SMC_NLA_DEV_PCI_DEVICE, smc_pci_dev.pci_device)) - goto errattr; - if (nla_put_string(skb, SMC_NLA_DEV_PCI_ID, smc_pci_dev.pci_id)) - goto errattr; + if (smcibdev->ibdev->dev.parent) { + memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); + pci_dev = to_pci_dev(smcibdev->ibdev->dev.parent); + smc_set_pci_values(pci_dev, &smc_pci_dev); + if (!smc_nl_handle_pci_values(&smc_pci_dev, skb)) + goto errattr; + } snprintf(smc_ibname, sizeof(smc_ibname), "%s", smcibdev->ibdev->name); if (nla_put_string(skb, SMC_NLA_DEV_IB_NAME, smc_ibname)) goto errattr; -- Gitee From f58c7ab3d9576f1ac3495121ecb7bf44f954cca1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 12 Jan 2021 17:21:21 +0100 Subject: [PATCH 13/20] smc: fix out of bound access in smc_nl_get_sys_info() mainline inclusion from mainline-v5.11-rc4 commit 25fe2c9c4cd2e97c5f5b69f3aefe69aad3057936 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=25fe2c9c4cd2e97c5f5b69f3aefe69aad3057936 -------------------------------- smc_clc_get_hostname() sets the host pointer to a buffer which is not NULL-terminated (see smc_clc_init()). Reported-by: syzbot+f4708c391121cfc58396@syzkaller.appspotmail.com Fixes: 099b990bd11a ("net/smc: Add support for obtaining system information") Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index f7ad52db6fcf..0c4b6080f2e9 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -248,7 +248,8 @@ int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb) goto errattr; smc_clc_get_hostname(&host); if (host) { - snprintf(hostname, sizeof(hostname), "%s", host); + memcpy(hostname, host, SMC_MAX_HOSTNAME_LEN); + hostname[SMC_MAX_HOSTNAME_LEN] = 0; if (nla_put_string(skb, SMC_NLA_SYS_LOCAL_HOST, hostname)) goto errattr; } -- Gitee From 8ec8041bd0547715c220ec4391af9a581ed7c63c Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 12 Jan 2021 17:21:22 +0100 Subject: [PATCH 14/20] net/smc: use memcpy instead of snprintf to avoid out of bounds read mainline inclusion from mainline-v5.11-rc4 commit 8a4465368964b4fbaf084760c94c7aabf61059fb category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=8a4465368964b4fbaf084760c94c7aabf61059fb -------------------------------- Using snprintf() to convert not null-terminated strings to null terminated strings may cause out of bounds read in the source string. Therefore use memcpy() and terminate the target string with a null afterwards. Fixes: a3db10efcc4c ("net/smc: Add support for obtaining SMCR device list") Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski Signed-off-by: Yingyu Zeng --- net/smc/smc_core.c | 17 +++++++++++------ net/smc/smc_ib.c | 6 +++--- net/smc/smc_ism.c | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 0c4b6080f2e9..2795d5c9ac5a 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -260,7 +260,8 @@ int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb) smc_ism_get_system_eid(smcd_dev, &seid); mutex_unlock(&smcd_dev_list.mutex); if (seid && smc_ism_is_v2_capable()) { - snprintf(smc_seid, sizeof(smc_seid), "%s", seid); + memcpy(smc_seid, seid, SMC_MAX_EID_LEN); + smc_seid[SMC_MAX_EID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_SYS_SEID, smc_seid)) goto errattr; } @@ -298,7 +299,8 @@ static int smc_nl_fill_lgr(struct smc_link_group *lgr, goto errattr; if (nla_put_u8(skb, SMC_NLA_LGR_R_VLAN_ID, lgr->vlan_id)) goto errattr; - snprintf(smc_target, sizeof(smc_target), "%s", lgr->pnet_id); + memcpy(smc_target, lgr->pnet_id, SMC_MAX_PNETID_LEN); + smc_target[SMC_MAX_PNETID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_LGR_R_PNETID, smc_target)) goto errattr; @@ -315,7 +317,7 @@ static int smc_nl_fill_lgr_link(struct smc_link_group *lgr, struct sk_buff *skb, struct netlink_callback *cb) { - char smc_ibname[IB_DEVICE_NAME_MAX + 1]; + char smc_ibname[IB_DEVICE_NAME_MAX]; u8 smc_gid_target[41]; struct nlattr *attrs; u32 link_uid = 0; @@ -464,7 +466,8 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, goto errattr; if (nla_put_u32(skb, SMC_NLA_LGR_D_CHID, smc_ism_get_chid(lgr->smcd))) goto errattr; - snprintf(smc_pnet, sizeof(smc_pnet), "%s", lgr->smcd->pnetid); + memcpy(smc_pnet, lgr->smcd->pnetid, SMC_MAX_PNETID_LEN); + smc_pnet[SMC_MAX_PNETID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_LGR_D_PNETID, smc_pnet)) goto errattr; @@ -477,10 +480,12 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, goto errv2attr; if (nla_put_u8(skb, SMC_NLA_LGR_V2_OS, lgr->peer_os)) goto errv2attr; - snprintf(smc_host, sizeof(smc_host), "%s", lgr->peer_hostname); + memcpy(smc_host, lgr->peer_hostname, SMC_MAX_HOSTNAME_LEN); + smc_host[SMC_MAX_HOSTNAME_LEN] = 0; if (nla_put_string(skb, SMC_NLA_LGR_V2_PEER_HOST, smc_host)) goto errv2attr; - snprintf(smc_eid, sizeof(smc_eid), "%s", lgr->negotiated_eid); + memcpy(smc_eid, lgr->negotiated_eid, SMC_MAX_EID_LEN); + smc_eid[SMC_MAX_EID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_LGR_V2_NEG_EID, smc_eid)) goto errv2attr; diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 075cc3cbf636..2e0d7aeefc41 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -371,8 +371,8 @@ static int smc_nl_handle_dev_port(struct sk_buff *skb, if (nla_put_u8(skb, SMC_NLA_DEV_PORT_PNET_USR, smcibdev->pnetid_by_user[port])) goto errattr; - snprintf(smc_pnet, sizeof(smc_pnet), "%s", - (char *)&smcibdev->pnetid[port]); + memcpy(smc_pnet, &smcibdev->pnetid[port], SMC_MAX_PNETID_LEN); + smc_pnet[SMC_MAX_PNETID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_DEV_PORT_PNETID, smc_pnet)) goto errattr; if (nla_put_u32(skb, SMC_NLA_DEV_PORT_NETDEV, @@ -414,7 +414,7 @@ static int smc_nl_handle_smcr_dev(struct smc_ib_device *smcibdev, struct sk_buff *skb, struct netlink_callback *cb) { - char smc_ibname[IB_DEVICE_NAME_MAX + 1]; + char smc_ibname[IB_DEVICE_NAME_MAX]; struct smc_pci_dev smc_pci_dev; struct pci_dev *pci_dev; unsigned char is_crit; diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index de34f57a6ede..967712ba52a0 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -250,7 +250,8 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, goto errattr; if (nla_put_u8(skb, SMC_NLA_DEV_PORT_PNET_USR, smcd->pnetid_by_user)) goto errportattr; - snprintf(smc_pnet, sizeof(smc_pnet), "%s", smcd->pnetid); + memcpy(smc_pnet, smcd->pnetid, SMC_MAX_PNETID_LEN); + smc_pnet[SMC_MAX_PNETID_LEN] = 0; if (nla_put_string(skb, SMC_NLA_DEV_PORT_PNETID, smc_pnet)) goto errportattr; -- Gitee From 6f7c18ba86b863fa0685b4afbef02773d3a74dc4 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Wed, 16 Jun 2021 16:52:55 +0200 Subject: [PATCH 15/20] net/smc: Add SMC statistics support mainline inclusion from mainline-v5.14-rc1 commit e0e4b8fa533858532f1b9ea9c6a4660d09beb37a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=e0e4b8fa533858532f1b9ea9c6a4660d09beb37a -------------------------------- Add the ability to collect SMC statistics information. Per-cpu variables are used to collect the statistic information for better performance and for reducing concurrency pitfalls. The code that is collecting statistic data is implemented in macros to increase code reuse and readability. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: David S. Miller Signed-off-by: Yingyu Zeng --- net/smc/Makefile | 2 +- net/smc/af_smc.c | 88 +++++++++++---- net/smc/smc_core.c | 13 ++- net/smc/smc_rx.c | 8 ++ net/smc/smc_stats.c | 35 ++++++ net/smc/smc_stats.h | 253 ++++++++++++++++++++++++++++++++++++++++++++ net/smc/smc_tx.c | 16 ++- 7 files changed, 392 insertions(+), 23 deletions(-) create mode 100644 net/smc/smc_stats.c create mode 100644 net/smc/smc_stats.h diff --git a/net/smc/Makefile b/net/smc/Makefile index 481a5d072f61..4444145a8ab3 100644 --- a/net/smc/Makefile +++ b/net/smc/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_SMC) += smc.o obj-$(CONFIG_SMC_DIAG) += smc_diag.o 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-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o smc-$(CONFIG_SYSCTL) += smc_sysctl.o diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 6acb92aa5fc6..777636bc5e3d 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -50,6 +50,7 @@ #include "smc_rx.h" #include "smc_close.h" #include "smc_sysctl.h" +#include "smc_stats.h" static DEFINE_MUTEX(smc_server_lgr_pending); /* serialize link group * creation on server @@ -623,6 +624,37 @@ static void smc_link_save_peer_info(struct smc_link *link, link->peer_mtu = clc->r0.qp_mtu; } +static void smc_stat_inc_fback_rsn_cnt(struct smc_sock *smc, + struct smc_stats_fback *fback_arr) +{ + int cnt; + + for (cnt = 0; cnt < SMC_MAX_FBACK_RSN_CNT; cnt++) { + if (fback_arr[cnt].fback_code == smc->fallback_rsn) { + fback_arr[cnt].count++; + break; + } + if (!fback_arr[cnt].fback_code) { + fback_arr[cnt].fback_code = smc->fallback_rsn; + fback_arr[cnt].count++; + break; + } + } +} + +static void smc_stat_fallback(struct smc_sock *smc) +{ + mutex_lock(&smc_stat_fback_rsn); + if (smc->listen_smc) { + smc_stat_inc_fback_rsn_cnt(smc, fback_rsn.srv); + fback_rsn.srv_fback_cnt++; + } else { + smc_stat_inc_fback_rsn_cnt(smc, fback_rsn.clnt); + fback_rsn.clnt_fback_cnt++; + } + mutex_unlock(&smc_stat_fback_rsn); +} + /* must be called under rcu read lock */ static void smc_fback_wakeup_waitqueue(struct smc_sock *smc, void *key) { @@ -748,7 +780,7 @@ static void smc_fback_replace_callbacks(struct smc_sock *smc) write_unlock_bh(&clcsk->sk_callback_lock); } -static int smc_switch_to_fallback(struct smc_sock *smc) +static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code) { int rc = 0; @@ -759,6 +791,8 @@ static int smc_switch_to_fallback(struct smc_sock *smc) } smc->use_fallback = true; + smc->fallback_rsn = reason_code; + smc_stat_fallback(smc); if (smc->sk.sk_socket && smc->sk.sk_socket->file) { smc->clcsock->file = smc->sk.sk_socket->file; smc->clcsock->file->private_data = smc->clcsock; @@ -781,13 +815,12 @@ static int smc_connect_fallback(struct smc_sock *smc, int reason_code) { int rc = 0; - rc = smc_switch_to_fallback(smc); + rc = smc_switch_to_fallback(smc, reason_code); if (rc) { /* fallback fails */ if (smc->sk.sk_state == SMC_INIT) sock_put(&smc->sk); /* passive closing */ return rc; } - smc->fallback_rsn = reason_code; smc_copy_sock_settings_to_clc(smc); smc->connect_nonblock = 0; if (smc->sk.sk_state == SMC_INIT) @@ -802,6 +835,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code, int rc; if (reason_code < 0) { /* error, fallback is not possible */ + this_cpu_inc(smc_stats->clnt_hshake_err_cnt); if (smc->sk.sk_state == SMC_INIT) sock_put(&smc->sk); /* passive closing */ return reason_code; @@ -809,6 +843,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code, if (reason_code != SMC_CLC_DECL_PEERDECL) { rc = smc_clc_send_decline(smc, reason_code, version); if (rc < 0) { + this_cpu_inc(smc_stats->clnt_hshake_err_cnt); if (smc->sk.sk_state == SMC_INIT) sock_put(&smc->sk); /* passive closing */ return rc; @@ -1263,6 +1298,7 @@ static int __smc_connect(struct smc_sock *smc) if (rc) goto vlan_cleanup; + SMC_STAT_CLNT_SUCC_INC(aclc); smc_connect_ism_vlan_cleanup(smc, ini); kfree(buf); kfree(ini); @@ -1638,6 +1674,7 @@ static void smc_listen_out_err(struct smc_sock *new_smc) { struct sock *newsmcsk = &new_smc->sk; + this_cpu_inc(smc_stats->srv_hshake_err_cnt); if (newsmcsk->sk_state == SMC_INIT) sock_put(&new_smc->sk); /* passive closing */ newsmcsk->sk_state = SMC_CLOSED; @@ -1655,12 +1692,11 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code, else smc_conn_free(&new_smc->conn); if (reason_code < 0 || - smc_switch_to_fallback(new_smc)) { + smc_switch_to_fallback(new_smc, reason_code)) { /* error, no fallback possible */ smc_listen_out_err(new_smc); return; } - new_smc->fallback_rsn = reason_code; if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) { if (smc_clc_send_decline(new_smc, reason_code, version) < 0) { smc_listen_out_err(new_smc); @@ -2020,13 +2056,11 @@ static void smc_listen_work(struct work_struct *work) /* check if peer is smc capable */ if (!tcp_sk(newclcsock->sk)->syn_smc) { - rc = smc_switch_to_fallback(new_smc); - if (rc) { + rc = smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC); + if (rc) smc_listen_out_err(new_smc); - } else { - new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC; + else smc_listen_out_connected(new_smc); - } return; } @@ -2103,6 +2137,7 @@ static void smc_listen_work(struct work_struct *work) } smc_conn_save_peer_info(new_smc, cclc); smc_listen_out_connected(new_smc); + SMC_STAT_SERV_SUCC_INC(ini); goto out_free; out_unlock: @@ -2320,10 +2355,9 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (msg->msg_flags & MSG_FASTOPEN) { /* not connected yet, fallback */ if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) { - rc = smc_switch_to_fallback(smc); + rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP); if (rc) goto out; - smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; } else { rc = -EINVAL; goto out; @@ -2335,10 +2369,12 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) goto out; } - if (smc->use_fallback) + if (smc->use_fallback) { rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len); - else + } else { rc = smc_tx_sendmsg(smc, msg, len); + SMC_STAT_TX_PAYLOAD(smc, len, rc); + } out: release_sock(sk); return rc; @@ -2373,6 +2409,7 @@ static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, } else { msg->msg_namelen = 0; rc = smc_rx_recvmsg(smc, msg, NULL, len, flags); + SMC_STAT_RX_PAYLOAD(smc, rc, rc); } out: @@ -2562,9 +2599,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, case TCP_FASTOPEN_NO_COOKIE: /* option not supported by SMC */ if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) { - rc = smc_switch_to_fallback(smc); - if (!rc) - smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; + rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP); } else { rc = -EINVAL; } @@ -2574,6 +2609,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_CLOSED) { if (val) { + SMC_STAT_INC(!smc->conn.lnk, ndly_cnt); smc_tx_pending(&smc->conn); cancel_delayed_work(&smc->conn.tx_work); } @@ -2584,6 +2620,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_CLOSED) { if (!val) { + SMC_STAT_INC(!smc->conn.lnk, cork_cnt); smc_tx_pending(&smc->conn); cancel_delayed_work(&smc->conn.tx_work); } @@ -2719,10 +2756,11 @@ static ssize_t smc_sendpage(struct socket *sock, struct page *page, goto out; } release_sock(sk); - if (smc->use_fallback) + if (smc->use_fallback) { rc = kernel_sendpage(smc->clcsock, page, offset, size, flags); - else { + } else { + SMC_STAT_INC(!smc->conn.lnk, sendpage_cnt); lock_sock(sk); rc = smc_tx_sendpage(smc, page, offset, size, flags); release_sock(sk); @@ -2775,6 +2813,7 @@ static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, flags = MSG_DONTWAIT; else flags = 0; + SMC_STAT_INC(!smc->conn.lnk, splice_cnt); rc = smc_rx_recvmsg(smc, NULL, pipe, len, flags); } out: @@ -2908,10 +2947,16 @@ static int __init smc_init(void) if (!smc_close_wq) goto out_alloc_hs_wq; + rc = smc_stats_init(); + if (rc) { + pr_err("%s: smc_stats_init fails with %d\n", __func__, rc); + goto out_alloc_wqs; + } + rc = smc_core_init(); if (rc) { pr_err("%s: smc_core_init fails with %d\n", __func__, rc); - goto out_alloc_wqs; + goto out_smc_stat; } rc = smc_llc_init(); @@ -2963,6 +3008,8 @@ static int __init smc_init(void) proto_unregister(&smc_proto); out_core: smc_core_exit(); +out_smc_stat: + smc_stats_exit(); out_alloc_wqs: destroy_workqueue(smc_close_wq); out_alloc_hs_wq: @@ -2988,6 +3035,7 @@ static void __exit smc_exit(void) destroy_workqueue(smc_close_wq); destroy_workqueue(smc_tcp_ls_wq); destroy_workqueue(smc_hs_wq); + smc_stats_exit(); proto_unregister(&smc_proto6); proto_unregister(&smc_proto); smc_pnet_exit(); diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 2795d5c9ac5a..de0fda76a49b 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -34,6 +34,7 @@ #include "smc_ism.h" #include "smc_sysctl.h" #include "smc_netlink.h" +#include "smc_stats.h" #define SMC_LGR_NUM_INCR 256 #define SMC_LGR_FREE_DELAY_SERV (600 * HZ) @@ -2228,6 +2229,7 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) struct smc_link_group *lgr = conn->lgr; struct list_head *buf_list; int bufsize, bufsize_comp; + bool is_dgraded = false; struct rw_semaphore *lock; /* lock buffer list */ if (is_rmb) @@ -2251,6 +2253,8 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) /* check for reusable slot in the link group */ buf_desc = smc_buf_get_slot(bufsize, lock, buf_list); if (buf_desc) { + SMC_STAT_RMB_SIZE(is_smcd, is_rmb, bufsize); + SMC_STAT_BUF_REUSE(is_smcd, is_rmb); break; /* found reusable slot */ } @@ -2261,9 +2265,16 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) if (PTR_ERR(buf_desc) == -ENOMEM) break; - if (IS_ERR(buf_desc)) + if (IS_ERR(buf_desc)) { + if (!is_dgraded) { + is_dgraded = true; + SMC_STAT_RMB_DOWNGRADED(is_smcd, is_rmb); + } continue; + } + SMC_STAT_RMB_ALLOC(is_smcd, is_rmb); + SMC_STAT_RMB_SIZE(is_smcd, is_rmb, bufsize); buf_desc->used = 1; down_write(lock); list_add(&buf_desc->list, buf_list); diff --git a/net/smc/smc_rx.c b/net/smc/smc_rx.c index 44583bf2df8e..de6e3ac5244e 100644 --- a/net/smc/smc_rx.c +++ b/net/smc/smc_rx.c @@ -21,6 +21,7 @@ #include "smc_cdc.h" #include "smc_tx.h" /* smc_tx_consumer_update() */ #include "smc_rx.h" +#include "smc_stats.h" /* callback implementation to wakeup consumers blocked with smc_rx_wait(). * indirectly called by smc_cdc_msg_recv_action(). @@ -285,6 +286,7 @@ static int smc_rx_recv_urg(struct smc_sock *smc, struct msghdr *msg, int len, conn->urg_state == SMC_URG_READ) return -EINVAL; + SMC_STAT_INC(!conn->lnk, urg_data_cnt); if (conn->urg_state == SMC_URG_VALID) { if (!(flags & MSG_PEEK)) smc->conn.urg_state = SMC_URG_READ; @@ -361,6 +363,12 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); + readable = atomic_read(&conn->bytes_to_rcv); + if (readable >= conn->rmb_desc->len) + SMC_STAT_RMB_RX_FULL(!conn->lnk); + + if (len < readable) + SMC_STAT_RMB_RX_SIZE_SMALL(!conn->lnk); /* we currently use 1 RMBE per RMB, so RMBE == RMB base addr */ rcvbuf_base = conn->rx_off + conn->rmb_desc->cpu_addr; diff --git a/net/smc/smc_stats.c b/net/smc/smc_stats.c new file mode 100644 index 000000000000..76e938388520 --- /dev/null +++ b/net/smc/smc_stats.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Shared Memory Communications over RDMA (SMC-R) and RoCE + * + * SMC statistics netlink routines + * + * Copyright IBM Corp. 2021 + * + * Author(s): Guvenc Gulce + */ +#include +#include +#include +#include +#include "smc_stats.h" + +/* serialize fallback reason statistic gathering */ +DEFINE_MUTEX(smc_stat_fback_rsn); +struct smc_stats __percpu *smc_stats; /* per cpu counters for SMC */ +struct smc_stats_reason fback_rsn; + +int __init smc_stats_init(void) +{ + memset(&fback_rsn, 0, sizeof(fback_rsn)); + smc_stats = alloc_percpu(struct smc_stats); + if (!smc_stats) + return -ENOMEM; + + return 0; +} + +void smc_stats_exit(void) +{ + free_percpu(smc_stats); +} diff --git a/net/smc/smc_stats.h b/net/smc/smc_stats.h new file mode 100644 index 000000000000..928372114cf1 --- /dev/null +++ b/net/smc/smc_stats.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Shared Memory Communications over RDMA (SMC-R) and RoCE + * + * Macros for SMC statistics + * + * Copyright IBM Corp. 2021 + * + * Author(s): Guvenc Gulce + */ + +#ifndef NET_SMC_SMC_STATS_H_ +#define NET_SMC_SMC_STATS_H_ +#include +#include +#include +#include +#include + +#include "smc_clc.h" + +#define SMC_MAX_FBACK_RSN_CNT 30 + +extern struct smc_stats __percpu *smc_stats; /* per cpu counters for SMC */ +extern struct smc_stats_reason fback_rsn; +extern struct mutex smc_stat_fback_rsn; + +enum { + SMC_BUF_8K, + SMC_BUF_16K, + SMC_BUF_32K, + SMC_BUF_64K, + SMC_BUF_128K, + SMC_BUF_256K, + SMC_BUF_512K, + SMC_BUF_1024K, + SMC_BUF_G_1024K, + SMC_BUF_MAX, +}; + +struct smc_stats_fback { + int fback_code; + u16 count; +}; + +struct smc_stats_reason { + struct smc_stats_fback srv[SMC_MAX_FBACK_RSN_CNT]; + struct smc_stats_fback clnt[SMC_MAX_FBACK_RSN_CNT]; + u64 srv_fback_cnt; + u64 clnt_fback_cnt; +}; + +struct smc_stats_rmbcnt { + u64 buf_size_small_peer_cnt; + u64 buf_size_small_cnt; + u64 buf_full_peer_cnt; + u64 buf_full_cnt; + u64 reuse_cnt; + u64 alloc_cnt; + u64 dgrade_cnt; +}; + +struct smc_stats_memsize { + u64 buf[SMC_BUF_MAX]; +}; + +struct smc_stats_tech { + struct smc_stats_memsize tx_rmbsize; + struct smc_stats_memsize rx_rmbsize; + struct smc_stats_memsize tx_pd; + struct smc_stats_memsize rx_pd; + struct smc_stats_rmbcnt rmb_tx; + struct smc_stats_rmbcnt rmb_rx; + u64 clnt_v1_succ_cnt; + u64 clnt_v2_succ_cnt; + u64 srv_v1_succ_cnt; + u64 srv_v2_succ_cnt; + u64 sendpage_cnt; + u64 urg_data_cnt; + u64 splice_cnt; + u64 cork_cnt; + u64 ndly_cnt; + u64 rx_bytes; + u64 tx_bytes; + u64 rx_cnt; + u64 tx_cnt; +}; + +struct smc_stats { + struct smc_stats_tech smc[2]; + u64 clnt_hshake_err_cnt; + u64 srv_hshake_err_cnt; +}; + +#define SMC_STAT_PAYLOAD_SUB(_tech, key, _len, _rc) \ +do { \ + typeof(_tech) t = (_tech); \ + typeof(_len) l = (_len); \ + int _pos = fls64((l) >> 13); \ + typeof(_rc) r = (_rc); \ + int m = SMC_BUF_MAX - 1; \ + this_cpu_inc((*smc_stats).smc[t].key ## _cnt); \ + if (r <= 0) \ + break; \ + _pos = (_pos < m) ? ((l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \ + this_cpu_inc((*smc_stats).smc[t].key ## _pd.buf[_pos]); \ + this_cpu_add((*smc_stats).smc[t].key ## _bytes, r); \ +} \ +while (0) + +#define SMC_STAT_TX_PAYLOAD(_smc, length, rcode) \ +do { \ + typeof(_smc) __smc = _smc; \ + typeof(length) _len = (length); \ + typeof(rcode) _rc = (rcode); \ + bool is_smcd = !__smc->conn.lnk; \ + if (is_smcd) \ + SMC_STAT_PAYLOAD_SUB(SMC_TYPE_D, tx, _len, _rc); \ + else \ + SMC_STAT_PAYLOAD_SUB(SMC_TYPE_R, tx, _len, _rc); \ +} \ +while (0) + +#define SMC_STAT_RX_PAYLOAD(_smc, length, rcode) \ +do { \ + typeof(_smc) __smc = _smc; \ + typeof(length) _len = (length); \ + typeof(rcode) _rc = (rcode); \ + bool is_smcd = !__smc->conn.lnk; \ + if (is_smcd) \ + SMC_STAT_PAYLOAD_SUB(SMC_TYPE_D, rx, _len, _rc); \ + else \ + SMC_STAT_PAYLOAD_SUB(SMC_TYPE_R, rx, _len, _rc); \ +} \ +while (0) + +#define SMC_STAT_RMB_SIZE_SUB(_tech, k, _len) \ +do { \ + typeof(_len) _l = (_len); \ + typeof(_tech) t = (_tech); \ + int _pos = fls((_l) >> 13); \ + int m = SMC_BUF_MAX - 1; \ + _pos = (_pos < m) ? ((_l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \ + this_cpu_inc((*smc_stats).smc[t].k ## _rmbsize.buf[_pos]); \ +} \ +while (0) + +#define SMC_STAT_RMB_SUB(type, t, key) \ + this_cpu_inc((*smc_stats).smc[t].rmb ## _ ## key.type ## _cnt) + +#define SMC_STAT_RMB_SIZE(_is_smcd, _is_rx, _len) \ +do { \ + typeof(_is_smcd) is_d = (_is_smcd); \ + typeof(_is_rx) is_r = (_is_rx); \ + typeof(_len) l = (_len); \ + if ((is_d) && (is_r)) \ + SMC_STAT_RMB_SIZE_SUB(SMC_TYPE_D, rx, l); \ + if ((is_d) && !(is_r)) \ + SMC_STAT_RMB_SIZE_SUB(SMC_TYPE_D, tx, l); \ + if (!(is_d) && (is_r)) \ + SMC_STAT_RMB_SIZE_SUB(SMC_TYPE_R, rx, l); \ + if (!(is_d) && !(is_r)) \ + SMC_STAT_RMB_SIZE_SUB(SMC_TYPE_R, tx, l); \ +} \ +while (0) + +#define SMC_STAT_RMB(type, _is_smcd, _is_rx) \ +do { \ + typeof(_is_smcd) is_d = (_is_smcd); \ + typeof(_is_rx) is_r = (_is_rx); \ + if ((is_d) && (is_r)) \ + SMC_STAT_RMB_SUB(type, SMC_TYPE_D, rx); \ + if ((is_d) && !(is_r)) \ + SMC_STAT_RMB_SUB(type, SMC_TYPE_D, tx); \ + if (!(is_d) && (is_r)) \ + SMC_STAT_RMB_SUB(type, SMC_TYPE_R, rx); \ + if (!(is_d) && !(is_r)) \ + SMC_STAT_RMB_SUB(type, SMC_TYPE_R, tx); \ +} \ +while (0) + +#define SMC_STAT_BUF_REUSE(is_smcd, is_rx) \ + SMC_STAT_RMB(reuse, is_smcd, is_rx) + +#define SMC_STAT_RMB_ALLOC(is_smcd, is_rx) \ + SMC_STAT_RMB(alloc, is_smcd, is_rx) + +#define SMC_STAT_RMB_DOWNGRADED(is_smcd, is_rx) \ + SMC_STAT_RMB(dgrade, is_smcd, is_rx) + +#define SMC_STAT_RMB_TX_PEER_FULL(is_smcd) \ + SMC_STAT_RMB(buf_full_peer, is_smcd, false) + +#define SMC_STAT_RMB_TX_FULL(is_smcd) \ + SMC_STAT_RMB(buf_full, is_smcd, false) + +#define SMC_STAT_RMB_TX_PEER_SIZE_SMALL(is_smcd) \ + SMC_STAT_RMB(buf_size_small_peer, is_smcd, false) + +#define SMC_STAT_RMB_TX_SIZE_SMALL(is_smcd) \ + SMC_STAT_RMB(buf_size_small, is_smcd, false) + +#define SMC_STAT_RMB_RX_SIZE_SMALL(is_smcd) \ + SMC_STAT_RMB(buf_size_small, is_smcd, true) + +#define SMC_STAT_RMB_RX_FULL(is_smcd) \ + SMC_STAT_RMB(buf_full, is_smcd, true) + +#define SMC_STAT_INC(is_smcd, type) \ +do { \ + if ((is_smcd)) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_D].type); \ + else \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_R].type); \ +} \ +while (0) + +#define SMC_STAT_CLNT_SUCC_INC(_aclc) \ +do { \ + typeof(_aclc) acl = (_aclc); \ + bool is_v2 = (acl->hdr.version == SMC_V2); \ + bool is_smcd = (acl->hdr.typev1 == SMC_TYPE_D); \ + if (is_v2 && is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_D].clnt_v2_succ_cnt); \ + else if (is_v2 && !is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_R].clnt_v2_succ_cnt); \ + else if (!is_v2 && is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_D].clnt_v1_succ_cnt); \ + else if (!is_v2 && !is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_R].clnt_v1_succ_cnt); \ +} \ +while (0) + +#define SMC_STAT_SERV_SUCC_INC(_ini) \ +do { \ + typeof(_ini) i = (_ini); \ + bool is_v2 = (i->smcd_version & SMC_V2); \ + bool is_smcd = (i->is_smcd); \ + if (is_v2 && is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_D].srv_v2_succ_cnt); \ + else if (is_v2 && !is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_R].srv_v2_succ_cnt); \ + else if (!is_v2 && is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_D].srv_v1_succ_cnt); \ + else if (!is_v2 && !is_smcd) \ + this_cpu_inc(smc_stats->smc[SMC_TYPE_R].srv_v1_succ_cnt); \ +} \ +while (0) + +int smc_stats_init(void) __init; +void smc_stats_exit(void); + +#endif /* NET_SMC_SMC_STATS_H_ */ diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 3a4ce37c9f82..f96e8a6a827b 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -27,6 +27,7 @@ #include "smc_close.h" #include "smc_ism.h" #include "smc_tx.h" +#include "smc_stats.h" #define SMC_TX_WORK_DELAY 0 @@ -44,6 +45,8 @@ static void smc_tx_write_space(struct sock *sk) /* similar to sk_stream_write_space */ if (atomic_read(&smc->conn.sndbuf_space) && sock) { + if (test_bit(SOCK_NOSPACE, &sock->flags)) + SMC_STAT_RMB_TX_FULL(!smc->conn.lnk); clear_bit(SOCK_NOSPACE, &sock->flags); rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); @@ -195,6 +198,15 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len) goto out_err; } + if (len > conn->sndbuf_desc->len) + SMC_STAT_RMB_TX_SIZE_SMALL(!conn->lnk); + + if (len > conn->peer_rmbe_size) + SMC_STAT_RMB_TX_PEER_SIZE_SMALL(!conn->lnk); + + if (msg->msg_flags & MSG_OOB) + SMC_STAT_INC(!conn->lnk, urg_data_cnt); + while (msg_data_left(msg)) { if (sk->sk_state == SMC_INIT) return -ENOTCONN; @@ -485,8 +497,10 @@ static int smc_tx_rdma_writes(struct smc_connection *conn, /* destination: RMBE */ /* cf. snd_wnd */ rmbespace = atomic_read(&conn->peer_rmbe_space); - if (rmbespace <= 0) + if (rmbespace <= 0) { + SMC_STAT_RMB_TX_PEER_FULL(!conn->lnk); return 0; + } smc_curs_copy(&prod, &conn->local_tx_ctrl.prod, conn); smc_curs_copy(&cons, &conn->local_rx_ctrl.cons, conn); -- Gitee From 0ead806271677f5dd8aaffafdf3dc0b28aa90406 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Wed, 16 Jun 2021 16:52:56 +0200 Subject: [PATCH 16/20] net/smc: Add netlink support for SMC statistics mainline inclusion from mainline-v5.14-rc1 commit 8c40602b4be17571dfd75102f4f1e690311c5210 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=8c40602b4be17571dfd75102f4f1e690311c5210 -------------------------------- Add the netlink function which collects the statistics information and delivers it to the userspace. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: David S. Miller Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 69 ++++++++++ net/smc/smc_netlink.c | 6 + net/smc/smc_stats.c | 279 +++++++++++++++++++++++++++++++++++++++ net/smc/smc_stats.h | 1 + 4 files changed, 355 insertions(+) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index 3e68da07fba2..f32f11b30963 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -47,6 +47,7 @@ enum { SMC_NETLINK_GET_LGR_SMCD, SMC_NETLINK_GET_DEV_SMCD, SMC_NETLINK_GET_DEV_SMCR, + SMC_NETLINK_GET_STATS, }; /* SMC_GENL_FAMILY top level attributes */ @@ -58,6 +59,7 @@ enum { SMC_GEN_LGR_SMCD, /* nest */ SMC_GEN_DEV_SMCD, /* nest */ SMC_GEN_DEV_SMCR, /* nest */ + SMC_GEN_STATS, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -159,4 +161,71 @@ enum { SMC_NLA_DEV_MAX = __SMC_NLA_DEV_MAX - 1 }; +/* SMC_NLA_STATS_T_TX(RX)_RMB_SIZE nested attributes */ +/* SMC_NLA_STATS_TX(RX)PLOAD_SIZE nested attributes */ +enum { + SMC_NLA_STATS_PLOAD_PAD, + SMC_NLA_STATS_PLOAD_8K, /* u64 */ + SMC_NLA_STATS_PLOAD_16K, /* u64 */ + SMC_NLA_STATS_PLOAD_32K, /* u64 */ + SMC_NLA_STATS_PLOAD_64K, /* u64 */ + SMC_NLA_STATS_PLOAD_128K, /* u64 */ + SMC_NLA_STATS_PLOAD_256K, /* u64 */ + SMC_NLA_STATS_PLOAD_512K, /* u64 */ + SMC_NLA_STATS_PLOAD_1024K, /* u64 */ + SMC_NLA_STATS_PLOAD_G_1024K, /* u64 */ + __SMC_NLA_STATS_PLOAD_MAX, + SMC_NLA_STATS_PLOAD_MAX = __SMC_NLA_STATS_PLOAD_MAX - 1 +}; + +/* SMC_NLA_STATS_T_TX(RX)_RMB_STATS nested attributes */ +enum { + SMC_NLA_STATS_RMB_PAD, + SMC_NLA_STATS_RMB_SIZE_SM_PEER_CNT, /* u64 */ + SMC_NLA_STATS_RMB_SIZE_SM_CNT, /* u64 */ + SMC_NLA_STATS_RMB_FULL_PEER_CNT, /* u64 */ + SMC_NLA_STATS_RMB_FULL_CNT, /* u64 */ + SMC_NLA_STATS_RMB_REUSE_CNT, /* u64 */ + SMC_NLA_STATS_RMB_ALLOC_CNT, /* u64 */ + SMC_NLA_STATS_RMB_DGRADE_CNT, /* u64 */ + __SMC_NLA_STATS_RMB_MAX, + SMC_NLA_STATS_RMB_MAX = __SMC_NLA_STATS_RMB_MAX - 1 +}; + +/* SMC_NLA_STATS_SMCD_TECH and _SMCR_TECH nested attributes */ +enum { + SMC_NLA_STATS_T_PAD, + SMC_NLA_STATS_T_TX_RMB_SIZE, /* nest */ + SMC_NLA_STATS_T_RX_RMB_SIZE, /* nest */ + SMC_NLA_STATS_T_TXPLOAD_SIZE, /* nest */ + SMC_NLA_STATS_T_RXPLOAD_SIZE, /* nest */ + SMC_NLA_STATS_T_TX_RMB_STATS, /* nest */ + SMC_NLA_STATS_T_RX_RMB_STATS, /* nest */ + SMC_NLA_STATS_T_CLNT_V1_SUCC, /* u64 */ + SMC_NLA_STATS_T_CLNT_V2_SUCC, /* u64 */ + SMC_NLA_STATS_T_SRV_V1_SUCC, /* u64 */ + SMC_NLA_STATS_T_SRV_V2_SUCC, /* u64 */ + SMC_NLA_STATS_T_SENDPAGE_CNT, /* u64 */ + SMC_NLA_STATS_T_SPLICE_CNT, /* u64 */ + SMC_NLA_STATS_T_CORK_CNT, /* u64 */ + SMC_NLA_STATS_T_NDLY_CNT, /* u64 */ + SMC_NLA_STATS_T_URG_DATA_CNT, /* u64 */ + SMC_NLA_STATS_T_RX_BYTES, /* u64 */ + SMC_NLA_STATS_T_TX_BYTES, /* u64 */ + SMC_NLA_STATS_T_RX_CNT, /* u64 */ + SMC_NLA_STATS_T_TX_CNT, /* u64 */ + __SMC_NLA_STATS_T_MAX, + SMC_NLA_STATS_T_MAX = __SMC_NLA_STATS_T_MAX - 1 +}; + +/* SMC_GEN_STATS attributes */ +enum { + SMC_NLA_STATS_PAD, + SMC_NLA_STATS_SMCD_TECH, /* nest */ + SMC_NLA_STATS_SMCR_TECH, /* nest */ + SMC_NLA_STATS_CLNT_HS_ERR_CNT, /* u64 */ + SMC_NLA_STATS_SRV_HS_ERR_CNT, /* u64 */ + __SMC_NLA_STATS_MAX, + SMC_NLA_STATS_MAX = __SMC_NLA_STATS_MAX - 1 +}; #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index 140419a19dbf..30e30b23370f 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -19,6 +19,7 @@ #include "smc_core.h" #include "smc_ism.h" #include "smc_ib.h" +#include "smc_stats.h" #include "smc_netlink.h" #define SMC_CMD_MAX_ATTR 1 @@ -55,6 +56,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smcr_nl_get_device, }, + { + .cmd = SMC_NETLINK_GET_STATS, + /* can be retrieved by unprivileged users */ + .dumpit = smc_nl_get_stats, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { diff --git a/net/smc/smc_stats.c b/net/smc/smc_stats.c index 76e938388520..72119d3d8558 100644 --- a/net/smc/smc_stats.c +++ b/net/smc/smc_stats.c @@ -12,6 +12,10 @@ #include #include #include +#include +#include +#include +#include "smc_netlink.h" #include "smc_stats.h" /* serialize fallback reason statistic gathering */ @@ -33,3 +37,278 @@ void smc_stats_exit(void) { free_percpu(smc_stats); } + +static int smc_nl_fill_stats_rmb_data(struct sk_buff *skb, + struct smc_stats *stats, int tech, + int type) +{ + struct smc_stats_rmbcnt *stats_rmb_cnt; + struct nlattr *attrs; + + if (type == SMC_NLA_STATS_T_TX_RMB_STATS) + stats_rmb_cnt = &stats->smc[tech].rmb_tx; + else + stats_rmb_cnt = &stats->smc[tech].rmb_rx; + + attrs = nla_nest_start(skb, type); + if (!attrs) + goto errout; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_REUSE_CNT, + stats_rmb_cnt->reuse_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_SIZE_SM_PEER_CNT, + stats_rmb_cnt->buf_size_small_peer_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_SIZE_SM_CNT, + stats_rmb_cnt->buf_size_small_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_FULL_PEER_CNT, + stats_rmb_cnt->buf_full_peer_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_FULL_CNT, + stats_rmb_cnt->buf_full_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_ALLOC_CNT, + stats_rmb_cnt->alloc_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_RMB_DGRADE_CNT, + stats_rmb_cnt->dgrade_cnt, + SMC_NLA_STATS_RMB_PAD)) + goto errattr; + + nla_nest_end(skb, attrs); + return 0; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + return -EMSGSIZE; +} + +static int smc_nl_fill_stats_bufsize_data(struct sk_buff *skb, + struct smc_stats *stats, int tech, + int type) +{ + struct smc_stats_memsize *stats_pload; + struct nlattr *attrs; + + if (type == SMC_NLA_STATS_T_TXPLOAD_SIZE) + stats_pload = &stats->smc[tech].tx_pd; + else if (type == SMC_NLA_STATS_T_RXPLOAD_SIZE) + stats_pload = &stats->smc[tech].rx_pd; + else if (type == SMC_NLA_STATS_T_TX_RMB_SIZE) + stats_pload = &stats->smc[tech].tx_rmbsize; + else if (type == SMC_NLA_STATS_T_RX_RMB_SIZE) + stats_pload = &stats->smc[tech].rx_rmbsize; + else + goto errout; + + attrs = nla_nest_start(skb, type); + if (!attrs) + goto errout; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_8K, + stats_pload->buf[SMC_BUF_8K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_16K, + stats_pload->buf[SMC_BUF_16K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_32K, + stats_pload->buf[SMC_BUF_32K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_64K, + stats_pload->buf[SMC_BUF_64K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_128K, + stats_pload->buf[SMC_BUF_128K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_256K, + stats_pload->buf[SMC_BUF_256K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_512K, + stats_pload->buf[SMC_BUF_512K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_1024K, + stats_pload->buf[SMC_BUF_1024K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_PLOAD_G_1024K, + stats_pload->buf[SMC_BUF_G_1024K], + SMC_NLA_STATS_PLOAD_PAD)) + goto errattr; + + nla_nest_end(skb, attrs); + return 0; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + return -EMSGSIZE; +} + +static int smc_nl_fill_stats_tech_data(struct sk_buff *skb, + struct smc_stats *stats, int tech) +{ + struct smc_stats_tech *smc_tech; + struct nlattr *attrs; + + smc_tech = &stats->smc[tech]; + if (tech == SMC_TYPE_D) + attrs = nla_nest_start(skb, SMC_NLA_STATS_SMCD_TECH); + else + attrs = nla_nest_start(skb, SMC_NLA_STATS_SMCR_TECH); + + if (!attrs) + goto errout; + if (smc_nl_fill_stats_rmb_data(skb, stats, tech, + SMC_NLA_STATS_T_TX_RMB_STATS)) + goto errattr; + if (smc_nl_fill_stats_rmb_data(skb, stats, tech, + SMC_NLA_STATS_T_RX_RMB_STATS)) + goto errattr; + if (smc_nl_fill_stats_bufsize_data(skb, stats, tech, + SMC_NLA_STATS_T_TXPLOAD_SIZE)) + goto errattr; + if (smc_nl_fill_stats_bufsize_data(skb, stats, tech, + SMC_NLA_STATS_T_RXPLOAD_SIZE)) + goto errattr; + if (smc_nl_fill_stats_bufsize_data(skb, stats, tech, + SMC_NLA_STATS_T_TX_RMB_SIZE)) + goto errattr; + if (smc_nl_fill_stats_bufsize_data(skb, stats, tech, + SMC_NLA_STATS_T_RX_RMB_SIZE)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_CLNT_V1_SUCC, + smc_tech->clnt_v1_succ_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_CLNT_V2_SUCC, + smc_tech->clnt_v2_succ_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_SRV_V1_SUCC, + smc_tech->srv_v1_succ_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_SRV_V2_SUCC, + smc_tech->srv_v2_succ_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_RX_BYTES, + smc_tech->rx_bytes, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_TX_BYTES, + smc_tech->tx_bytes, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_RX_CNT, + smc_tech->rx_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_TX_CNT, + smc_tech->tx_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_SENDPAGE_CNT, + smc_tech->sendpage_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_CORK_CNT, + smc_tech->cork_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_NDLY_CNT, + smc_tech->ndly_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_SPLICE_CNT, + smc_tech->splice_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_URG_DATA_CNT, + smc_tech->urg_data_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + + nla_nest_end(skb, attrs); + return 0; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + return -EMSGSIZE; +} + +int smc_nl_get_stats(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + struct smc_stats *stats; + struct nlattr *attrs; + int cpu, i, size; + void *nlh; + u64 *src; + u64 *sum; + + if (cb_ctx->pos[0]) + goto errmsg; + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_STATS); + if (!nlh) + goto errmsg; + + attrs = nla_nest_start(skb, SMC_GEN_STATS); + if (!attrs) + goto errnest; + stats = kzalloc(sizeof(*stats), GFP_KERNEL); + if (!stats) + goto erralloc; + size = sizeof(*stats) / sizeof(u64); + for_each_possible_cpu(cpu) { + src = (u64 *)per_cpu_ptr(smc_stats, cpu); + sum = (u64 *)stats; + for (i = 0; i < size; i++) + *(sum++) += *(src++); + } + if (smc_nl_fill_stats_tech_data(skb, stats, SMC_TYPE_D)) + goto errattr; + if (smc_nl_fill_stats_tech_data(skb, stats, SMC_TYPE_R)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_CLNT_HS_ERR_CNT, + stats->clnt_hshake_err_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_STATS_SRV_HS_ERR_CNT, + stats->srv_hshake_err_cnt, + SMC_NLA_STATS_PAD)) + goto errattr; + + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + cb_ctx->pos[0] = 1; + kfree(stats); + return skb->len; + +errattr: + kfree(stats); +erralloc: + nla_nest_cancel(skb, attrs); +errnest: + genlmsg_cancel(skb, nlh); +errmsg: + return skb->len; +} diff --git a/net/smc/smc_stats.h b/net/smc/smc_stats.h index 928372114cf1..84baaca59eaf 100644 --- a/net/smc/smc_stats.h +++ b/net/smc/smc_stats.h @@ -247,6 +247,7 @@ do { \ } \ while (0) +int smc_nl_get_stats(struct sk_buff *skb, struct netlink_callback *cb); int smc_stats_init(void) __init; void smc_stats_exit(void); -- Gitee From 30b536683c3884fd6827d2e8bbc4408cf7ccc16c Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Wed, 16 Jun 2021 16:52:57 +0200 Subject: [PATCH 17/20] net/smc: Add netlink support for SMC fallback statistics mainline inclusion from mainline-v5.14-rc1 commit f0dd7bf5e33066e554442c509ef6351728b95b51 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=f0dd7bf5e33066e554442c509ef6351728b95b51 -------------------------------- Add support to collect more detailed SMC fallback reason statistics and provide these statistics to user space on the netlink interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: David S. Miller Signed-off-by: Yingyu Zeng --- include/uapi/linux/smc.h | 14 ++++++ net/smc/smc_netlink.c | 5 +++ net/smc/smc_netlink.h | 2 +- net/smc/smc_stats.c | 92 ++++++++++++++++++++++++++++++++++++++++ net/smc/smc_stats.h | 1 + 5 files changed, 113 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/smc.h b/include/uapi/linux/smc.h index f32f11b30963..0f7f87c70baf 100644 --- a/include/uapi/linux/smc.h +++ b/include/uapi/linux/smc.h @@ -48,6 +48,7 @@ enum { SMC_NETLINK_GET_DEV_SMCD, SMC_NETLINK_GET_DEV_SMCR, SMC_NETLINK_GET_STATS, + SMC_NETLINK_GET_FBACK_STATS, }; /* SMC_GENL_FAMILY top level attributes */ @@ -60,6 +61,7 @@ enum { SMC_GEN_DEV_SMCD, /* nest */ SMC_GEN_DEV_SMCR, /* nest */ SMC_GEN_STATS, /* nest */ + SMC_GEN_FBACK_STATS, /* nest */ __SMC_GEN_MAX, SMC_GEN_MAX = __SMC_GEN_MAX - 1 }; @@ -228,4 +230,16 @@ enum { __SMC_NLA_STATS_MAX, SMC_NLA_STATS_MAX = __SMC_NLA_STATS_MAX - 1 }; + +/* SMC_GEN_FBACK_STATS attributes */ +enum { + SMC_NLA_FBACK_STATS_PAD, + SMC_NLA_FBACK_STATS_TYPE, /* u8 */ + SMC_NLA_FBACK_STATS_SRV_CNT, /* u64 */ + SMC_NLA_FBACK_STATS_CLNT_CNT, /* u64 */ + SMC_NLA_FBACK_STATS_RSN_CODE, /* u32 */ + SMC_NLA_FBACK_STATS_RSN_CNT, /* u16 */ + __SMC_NLA_FBACK_STATS_MAX, + SMC_NLA_FBACK_STATS_MAX = __SMC_NLA_FBACK_STATS_MAX - 1 +}; #endif /* _UAPI_LINUX_SMC_H */ diff --git a/net/smc/smc_netlink.c b/net/smc/smc_netlink.c index 30e30b23370f..6fb6f96c1d17 100644 --- a/net/smc/smc_netlink.c +++ b/net/smc/smc_netlink.c @@ -61,6 +61,11 @@ static const struct genl_ops smc_gen_nl_ops[] = { /* can be retrieved by unprivileged users */ .dumpit = smc_nl_get_stats, }, + { + .cmd = SMC_NETLINK_GET_FBACK_STATS, + /* can be retrieved by unprivileged users */ + .dumpit = smc_nl_get_fback_stats, + }, }; static const struct nla_policy smc_gen_nl_policy[2] = { diff --git a/net/smc/smc_netlink.h b/net/smc/smc_netlink.h index 3477265cba6c..5ce2c0a89ccd 100644 --- a/net/smc/smc_netlink.h +++ b/net/smc/smc_netlink.h @@ -18,7 +18,7 @@ extern struct genl_family smc_gen_nl_family; struct smc_nl_dmp_ctx { - int pos[2]; + int pos[3]; }; static inline struct smc_nl_dmp_ctx *smc_nl_dmp_ctx(struct netlink_callback *c) diff --git a/net/smc/smc_stats.c b/net/smc/smc_stats.c index 72119d3d8558..b3d279d29c52 100644 --- a/net/smc/smc_stats.c +++ b/net/smc/smc_stats.c @@ -312,3 +312,95 @@ int smc_nl_get_stats(struct sk_buff *skb, errmsg: return skb->len; } + +static int smc_nl_get_fback_details(struct sk_buff *skb, + struct netlink_callback *cb, int pos, + bool is_srv) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + int cnt_reported = cb_ctx->pos[2]; + struct smc_stats_fback *trgt_arr; + struct nlattr *attrs; + int rc = 0; + void *nlh; + + if (is_srv) + trgt_arr = &fback_rsn.srv[0]; + else + trgt_arr = &fback_rsn.clnt[0]; + if (!trgt_arr[pos].fback_code) + return -ENODATA; + nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &smc_gen_nl_family, NLM_F_MULTI, + SMC_NETLINK_GET_FBACK_STATS); + if (!nlh) + goto errmsg; + attrs = nla_nest_start(skb, SMC_GEN_FBACK_STATS); + if (!attrs) + goto errout; + if (nla_put_u8(skb, SMC_NLA_FBACK_STATS_TYPE, is_srv)) + goto errattr; + if (!cnt_reported) { + if (nla_put_u64_64bit(skb, SMC_NLA_FBACK_STATS_SRV_CNT, + fback_rsn.srv_fback_cnt, + SMC_NLA_FBACK_STATS_PAD)) + goto errattr; + if (nla_put_u64_64bit(skb, SMC_NLA_FBACK_STATS_CLNT_CNT, + fback_rsn.clnt_fback_cnt, + SMC_NLA_FBACK_STATS_PAD)) + goto errattr; + cnt_reported = 1; + } + + if (nla_put_u32(skb, SMC_NLA_FBACK_STATS_RSN_CODE, + trgt_arr[pos].fback_code)) + goto errattr; + if (nla_put_u16(skb, SMC_NLA_FBACK_STATS_RSN_CNT, + trgt_arr[pos].count)) + goto errattr; + + cb_ctx->pos[2] = cnt_reported; + nla_nest_end(skb, attrs); + genlmsg_end(skb, nlh); + return rc; + +errattr: + nla_nest_cancel(skb, attrs); +errout: + genlmsg_cancel(skb, nlh); +errmsg: + return -EMSGSIZE; +} + +int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); + int rc_srv = 0, rc_clnt = 0, k; + int skip_serv = cb_ctx->pos[1]; + int snum = cb_ctx->pos[0]; + bool is_srv = true; + + mutex_lock(&smc_stat_fback_rsn); + for (k = 0; k < SMC_MAX_FBACK_RSN_CNT; k++) { + if (k < snum) + continue; + if (!skip_serv) { + rc_srv = smc_nl_get_fback_details(skb, cb, k, is_srv); + if (rc_srv && rc_srv != ENODATA) + break; + } else { + skip_serv = 0; + } + rc_clnt = smc_nl_get_fback_details(skb, cb, k, !is_srv); + if (rc_clnt && rc_clnt != ENODATA) { + skip_serv = 1; + break; + } + if (rc_clnt == ENODATA && rc_srv == ENODATA) + break; + } + mutex_unlock(&smc_stat_fback_rsn); + cb_ctx->pos[1] = skip_serv; + cb_ctx->pos[0] = k; + return skb->len; +} diff --git a/net/smc/smc_stats.h b/net/smc/smc_stats.h index 84baaca59eaf..7c35b22d9e29 100644 --- a/net/smc/smc_stats.h +++ b/net/smc/smc_stats.h @@ -248,6 +248,7 @@ do { \ while (0) int smc_nl_get_stats(struct sk_buff *skb, struct netlink_callback *cb); +int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb); int smc_stats_init(void) __init; void smc_stats_exit(void); -- Gitee From 81e6fafba156f0ee32cbb2e079b8449b70423a3e Mon Sep 17 00:00:00 2001 From: Litao Jiao Date: Wed, 29 Nov 2023 07:30:49 -0500 Subject: [PATCH 18/20] net/smc: Fix ENODATA tests in smc_nl_get_fback_stats() mainline inclusion from mainline-v5.14-rc1 commit 1a1100d53f12451d50bc5ebbc941517760912ab8 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=1a1100d53f12451d50bc5ebbc941517760912ab8 -------------------------------- These functions return negative ENODATA but the minus sign was left out in the tests. Fixes: f0dd7bf5e330 ("net/smc: Add netlink support for SMC fallback statistics") Signed-off-by: Dan Carpenter Acked-by: Guvenc Gulce Signed-off-by: David S. Miller --- net/smc/smc_stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/smc/smc_stats.c b/net/smc/smc_stats.c index b3d279d29c52..44491016707d 100644 --- a/net/smc/smc_stats.c +++ b/net/smc/smc_stats.c @@ -386,17 +386,17 @@ int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb) continue; if (!skip_serv) { rc_srv = smc_nl_get_fback_details(skb, cb, k, is_srv); - if (rc_srv && rc_srv != ENODATA) + if (rc_srv && rc_srv != -ENODATA) break; } else { skip_serv = 0; } rc_clnt = smc_nl_get_fback_details(skb, cb, k, !is_srv); - if (rc_clnt && rc_clnt != ENODATA) { + if (rc_clnt && rc_clnt != -ENODATA) { skip_serv = 1; break; } - if (rc_clnt == ENODATA && rc_srv == ENODATA) + if (rc_clnt == -ENODATA && rc_srv == -ENODATA) break; } mutex_unlock(&smc_stat_fback_rsn); -- Gitee From 1cdac2b78a9979e295f1f9b974437f18e560f30e Mon Sep 17 00:00:00 2001 From: Litao Jiao Date: Wed, 29 Nov 2023 07:41:37 -0500 Subject: [PATCH 19/20] net/smc: Ensure correct state of the socket in send path mainline inclusion from mainline-v5.14-rc1 commit 17081633e22d83be928a779fd7acd04b247dec90 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=17081633e22d83be928a779fd7acd04b247dec90 -------------------------------- When smc_sendmsg() is called before the SMC socket initialization has completed, smc_tx_sendmsg() will access un-initialized fields of the SMC socket which results in a null-pointer dereference. Fix this by checking the socket state first in smc_tx_sendmsg(). Fixes: e0e4b8f ("net/smc: Add SMC statistics support") Reported-by: syzbot+5dda108b672b54141857@syzkaller.appspotmail.com Reviewed-by: Karsten Graul Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: David S. Miller --- net/smc/smc_tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index f96e8a6a827b..d6b9ccb88e65 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -198,6 +198,9 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len) goto out_err; } + if (sk->sk_state == SMC_INIT) + return -ENOTCONN; + if (len > conn->sndbuf_desc->len) SMC_STAT_RMB_TX_SIZE_SMALL(!conn->lnk); @@ -208,8 +211,6 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len) SMC_STAT_INC(!conn->lnk, urg_data_cnt); while (msg_data_left(msg)) { - if (sk->sk_state == SMC_INIT) - return -ENOTCONN; if (smc->sk.sk_shutdown & SEND_SHUTDOWN || (smc->sk.sk_err == ECONNABORTED) || conn->killed) -- Gitee From 7c3101c4f09cbbdec490c39a239227052da61e34 Mon Sep 17 00:00:00 2001 From: Litao Jiao Date: Wed, 29 Nov 2023 07:49:45 -0500 Subject: [PATCH 20/20] net/smc: Fix pos miscalculation in statistics mainline inclusion from mainline-v6.6-rc6 commit a950a5921db450c74212327f69950ff03419483a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=a950a5921db450c74212327f69950ff03419483a -------------------------------- SMC_STAT_PAYLOAD_SUB(_smc_stats, _tech, key, _len, _rc) will calculate wrong bucket positions for payloads of exactly 4096 bytes and (1 << (m + 12)) bytes, with m == SMC_BUF_MAX - 1. Intended bucket distribution: Assume l == size of payload, m == SMC_BUF_MAX - 1. Bucket 0 : 0 < l <= 2^13 Bucket n, 1 <= n <= m-1 : 2^(n+12) < l <= 2^(n+13) Bucket m : l > 2^(m+12) Current solution: _pos = fls64((l) >> 13) [...] _pos = (_pos < m) ? ((l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m For l == 4096, _pos == -1, but should be _pos == 0. For l == (1 << (m + 12)), _pos == m, but should be _pos == m - 1. In order to avoid special treatment of these corner cases, the calculation is adjusted. The new solution first subtracts the length by one, and then calculates the correct bucket by shifting accordingly, i.e. _pos = fls64((l - 1) >> 13), l > 0. This not only fixes the issues named above, but also makes the whole bucket assignment easier to follow. Same is done for SMC_STAT_RMB_SIZE_SUB(_smc_stats, _tech, k, _len), where the calculation of the bucket position is similar to the one named above. Fixes: e0e4b8f ("net/smc: Add SMC statistics support") Suggested-by: Halil Pasic Signed-off-by: Nils Hoppmann Reviewed-by: Halil Pasic Reviewed-by: Wenjia Zhang Reviewed-by: Dust Li Signed-off-by: David S. Miller --- net/smc/smc_stats.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/smc/smc_stats.h b/net/smc/smc_stats.h index 7c35b22d9e29..c159acd932c5 100644 --- a/net/smc/smc_stats.h +++ b/net/smc/smc_stats.h @@ -96,13 +96,14 @@ struct smc_stats { do { \ typeof(_tech) t = (_tech); \ typeof(_len) l = (_len); \ - int _pos = fls64((l) >> 13); \ + int _pos; \ typeof(_rc) r = (_rc); \ int m = SMC_BUF_MAX - 1; \ this_cpu_inc((*smc_stats).smc[t].key ## _cnt); \ - if (r <= 0) \ + if (r <= 0 || l <= 0) \ break; \ - _pos = (_pos < m) ? ((l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \ + _pos = fls64((l - 1) >> 13); \ + _pos = (_pos <= m) ? _pos : m; \ this_cpu_inc((*smc_stats).smc[t].key ## _pd.buf[_pos]); \ this_cpu_add((*smc_stats).smc[t].key ## _bytes, r); \ } \ @@ -138,9 +139,12 @@ while (0) do { \ typeof(_len) _l = (_len); \ typeof(_tech) t = (_tech); \ - int _pos = fls((_l) >> 13); \ + int _pos; \ int m = SMC_BUF_MAX - 1; \ - _pos = (_pos < m) ? ((_l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \ + if (_l <= 0) \ + break; \ + _pos = fls((_l - 1) >> 13); \ + _pos = (_pos <= m) ? _pos : m; \ this_cpu_inc((*smc_stats).smc[t].k ## _rmbsize.buf[_pos]); \ } \ while (0) -- Gitee