From e8372d9d21451a2f2947c2b63b5184f3d4d0bff9 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:43 +0100 Subject: net/smc: Introduce generic netlink interface for diagnostic purposes 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 --- include/uapi/linux/smc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/uapi') 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 */ -- cgit v1.3-14-g43fede From 099b990bd11a3a96b5d59973f482018e5cbde6c3 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:44 +0100 Subject: net/smc: Add support for obtaining system information 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 --- 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(+) (limited to 'include/uapi') 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 696d89c2dce4..e286dafd6e88 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -772,6 +772,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 49752c997c51..32d37f7b70f2 100644 --- a/net/smc/smc_clc.h +++ b/net/smc/smc_clc.h @@ -334,5 +334,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 0088511e30bf..c7b1c62c2f2e 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 @@ -30,6 +32,7 @@ #include "smc_cdc.h" #include "smc_close.h" #include "smc_ism.h" +#include "smc_netlink.h" #define SMC_LGR_NUM_INCR 256 #define SMC_LGR_FREE_DELAY_SERV (600 * HZ) @@ -214,6 +217,63 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn) conn->lgr = NULL; } +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 3a1bb8e4b81f..eaed25d4e76b 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" @@ -413,6 +414,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); -- cgit v1.3-14-g43fede From e9b8c845cb342a3ab3d92235a54d0d1ad06d7204 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:45 +0100 Subject: net/smc: Introduce SMCR get linkgroup command 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 --- 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(+) (limited to 'include/uapi') 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 c7b1c62c2f2e..e21d068191ad 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -274,6 +274,91 @@ errmsg: 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 eaed25d4e76b..662315beb605 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -415,6 +415,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] = { -- cgit v1.3-14-g43fede From 5a7e09d58f3fe2f0d5e8f0da4b1f686491245eb5 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:46 +0100 Subject: net/smc: Introduce SMCR get link command 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 --- 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(-) (limited to 'include/uapi') 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 e21d068191ad..5ad4b742dcc1 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -307,11 +307,74 @@ errout: 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, @@ -322,6 +385,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: @@ -332,7 +404,8 @@ errmsg: 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; @@ -343,7 +416,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++; @@ -355,7 +428,17 @@ errout: 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 662315beb605..7995621f318d 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -367,6 +367,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; @@ -416,6 +429,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 c2225231f679..c952986a6aca 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] = { -- cgit v1.3-14-g43fede From 8f9dde4bf230f5c54a24c42a989dd9d88ec95695 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:47 +0100 Subject: net/smc: Add SMC-D Linkgroup diagnostic support Deliver SMCD Linkgroup information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski --- 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(+) (limited to 'include/uapi') 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 5ad4b742dcc1..ac2cc593f25f 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -426,6 +426,130 @@ errout: 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; @@ -442,6 +566,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 7995621f318d..0b6899a7f634 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -430,6 +430,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] = { -- cgit v1.3-14-g43fede From aaf95523d5824ebc2c8c185a2de51063a750c446 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:48 +0100 Subject: net/smc: Add support for obtaining SMCD device list Deliver SMCD device information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski --- 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(+) (limited to 'include/uapi') 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 0b6899a7f634..e8e448771f85 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 @@ -380,6 +382,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 2456ee8228cd..524ef64a191a 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] = { -- cgit v1.3-14-g43fede From a3db10efcc4cc9c03a6375920179ade75ea2df7a Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 1 Dec 2020 20:20:49 +0100 Subject: net/smc: Add support for obtaining SMCR device list Deliver SMCR device information via netlink based diagnostic interface. Signed-off-by: Guvenc Gulce Signed-off-by: Karsten Graul Signed-off-by: Jakub Kicinski --- 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(-) (limited to 'include/uapi') 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 ac2cc593f25f..59342b519e34 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -38,7 +38,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 61b025c912a9..89ea10675a7d 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 ab37da341fa8..3085f5180da7 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; @@ -91,4 +92,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] = { -- cgit v1.3-14-g43fede