Merge branch 'net-smc-add-support-for-generic-netlink-api'
Karsten Graul says: ==================== net/smc: Add support for generic netlink API Up to version 4 this patch series was using the sock_diag netlink infrastructure. This version is using the generic netlink API. Generic netlink API offers a better type safety between kernel and userspace communication. Using the generic netlink API the smc module can now provide information about SMC linkgroups, links and devices (both for SMC-R and SMC-D). v2: Add missing include to uapi header smc_diag.h. v3: Apply code style recommendations from review comments. Instead of using EXPORTs to allow the smc_diag module to access data of the smc module, introduce struct smc_diag_ops and let smc_diag access the required data using function pointers. v4: Address checkpatch.pl warnings. Do not use static inline for functions. v5: Use generic netlink API instead of the sock_diag netlink infrastructure. v6: Integrate more review comments from Jakub. v7: Use nla_nest_start() with the new family. Use .maxattr=1 in the genl family and define one entry for attribute 1 in the policy to reject this attritbute for all commands. All other possible attributes are rejected because NL_VALIDATE_STRICT is set for the policy implicitely, which includes NL_VALIDATE_MAXTYPE. Setting policy[0].strict_start_type=1 does not work here because there is no valid attribute defined for this family, only plain commands. For any type > maxtype (which is .maxattr) validate_nla() would return 0 to userspace instead of -EINVAL. What helps here is __nla_validate_parse() which checks for type > maxtype and returns -EINVAL when NL_VALIDATE_MAXTYPE is set. This requires the one entry for type == .maxattr with .type = NLA_REJECT in the nla_policy. When a future command wants to allow attributes then it can easily specify a dedicated .policy for this new command in the genl_ops array. This dedicated policy overlays the global policy specified in the genl_family structure. ==================== Link: https://lore.kernel.org/r/20201201192049.53517-1-kgraul@linux.ibm.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
06f90dde4e
@ -33,4 +33,130 @@ 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
|
||||
|
||||
#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_NETLINK_GET_DEV_SMCR,
|
||||
};
|
||||
|
||||
/* SMC_GENL_FAMILY top level attributes */
|
||||
enum {
|
||||
SMC_GEN_UNSPEC,
|
||||
SMC_GEN_SYS_INFO, /* nest */
|
||||
SMC_GEN_LGR_SMCR, /* nest */
|
||||
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
|
||||
};
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/* 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,
|
||||
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
|
||||
};
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/* 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 and SMC_GEN_DEV_SMCR 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_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 */
|
||||
|
@ -2,4 +2,4 @@
|
||||
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
|
||||
|
@ -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"
|
||||
@ -552,8 +553,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code,
|
||||
return smc_connect_fallback(smc, reason_code);
|
||||
}
|
||||
|
||||
/* abort connecting */
|
||||
static void smc_connect_abort(struct smc_sock *smc, int local_first)
|
||||
static void smc_conn_abort(struct smc_sock *smc, int local_first)
|
||||
{
|
||||
if (local_first)
|
||||
smc_lgr_cleanup_early(&smc->conn);
|
||||
@ -669,7 +669,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 */
|
||||
@ -814,7 +814,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
|
||||
|
||||
return 0;
|
||||
connect_abort:
|
||||
smc_connect_abort(smc, ini->first_contact_local);
|
||||
smc_conn_abort(smc, ini->first_contact_local);
|
||||
mutex_unlock(&smc_client_lgr_pending);
|
||||
smc->connect_nonblock = 0;
|
||||
|
||||
@ -893,7 +893,7 @@ static int smc_connect_ism(struct smc_sock *smc,
|
||||
|
||||
return 0;
|
||||
connect_abort:
|
||||
smc_connect_abort(smc, ini->first_contact_local);
|
||||
smc_conn_abort(smc, ini->first_contact_local);
|
||||
mutex_unlock(&smc_server_lgr_pending);
|
||||
smc->connect_nonblock = 0;
|
||||
|
||||
@ -921,7 +921,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;
|
||||
@ -946,9 +946,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)) {
|
||||
@ -1321,10 +1321,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
|
||||
int local_first, u8 version)
|
||||
{
|
||||
/* RDMA setup failed, switch back to TCP */
|
||||
if (local_first)
|
||||
smc_lgr_cleanup_early(&new_smc->conn);
|
||||
else
|
||||
smc_conn_free(&new_smc->conn);
|
||||
smc_conn_abort(new_smc, local_first);
|
||||
if (reason_code < 0) { /* error, no fallback possible */
|
||||
smc_listen_out_err(new_smc);
|
||||
return;
|
||||
@ -1359,7 +1356,7 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
|
||||
rc = SMC_CLC_DECL_PEERNOSMC;
|
||||
goto out;
|
||||
}
|
||||
if (!smc_ism_v2_capable) {
|
||||
if (!smc_ism_is_v2_capable()) {
|
||||
ini->smcd_version &= ~SMC_V2;
|
||||
rc = SMC_CLC_DECL_NOISM2SUPP;
|
||||
goto out;
|
||||
@ -1430,10 +1427,7 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
|
||||
/* Create send and receive buffers */
|
||||
rc = smc_buf_create(new_smc, true);
|
||||
if (rc) {
|
||||
if (ini->first_contact_local)
|
||||
smc_lgr_cleanup_early(&new_smc->conn);
|
||||
else
|
||||
smc_conn_free(&new_smc->conn);
|
||||
smc_conn_abort(new_smc, ini->first_contact_local);
|
||||
return (rc == -ENOSPC) ? SMC_CLC_DECL_MAX_DMB :
|
||||
SMC_CLC_DECL_MEM;
|
||||
}
|
||||
@ -1688,7 +1682,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;
|
||||
@ -2502,10 +2496,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_hs_wq = alloc_workqueue("smc_hs_wq", 0, 0);
|
||||
if (!smc_hs_wq)
|
||||
@ -2576,6 +2574,8 @@ out_alloc_hs_wq:
|
||||
destroy_workqueue(smc_hs_wq);
|
||||
out_pnet:
|
||||
smc_pnet_exit();
|
||||
out_nl:
|
||||
smc_nl_exit();
|
||||
out_pernet_subsys:
|
||||
unregister_pernet_subsys(&smc_net_ops);
|
||||
|
||||
@ -2593,6 +2593,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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/smc.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/sock.h>
|
||||
#include <rdma/ib_verbs.h>
|
||||
@ -30,12 +32,13 @@
|
||||
#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)
|
||||
#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,
|
||||
@ -63,6 +66,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
|
||||
@ -139,6 +152,7 @@ static int smcr_lgr_conn_assign_link(struct smc_connection *conn, bool first)
|
||||
}
|
||||
if (!conn->lnk)
|
||||
return SMC_CLC_DECL_NOACTLINK;
|
||||
atomic_inc(&conn->lnk->conn_cnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -180,6 +194,8 @@ static void __smc_lgr_unregister_conn(struct smc_connection *conn)
|
||||
struct smc_link_group *lgr = conn->lgr;
|
||||
|
||||
rb_erase(&conn->alert_node, &lgr->conns_all);
|
||||
if (conn->lnk)
|
||||
atomic_dec(&conn->lnk->conn_cnt);
|
||||
lgr->conns_num--;
|
||||
conn->alert_token_local = 0;
|
||||
sock_put(&smc->sk); /* sock_hold in smc_lgr_register_conn() */
|
||||
@ -201,6 +217,361 @@ 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;
|
||||
}
|
||||
|
||||
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_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,
|
||||
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,
|
||||
SMC_NETLINK_GET_LGR_SMCR);
|
||||
if (!nlh)
|
||||
goto errmsg;
|
||||
if (smc_nl_fill_lgr(lgr, skb, cb))
|
||||
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:
|
||||
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,
|
||||
bool list_links)
|
||||
{
|
||||
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, list_links))
|
||||
goto errout;
|
||||
next:
|
||||
num++;
|
||||
}
|
||||
errout:
|
||||
spin_unlock_bh(&smc_lgr->lock);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -300,6 +671,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)
|
||||
{
|
||||
@ -313,7 +693,10 @@ 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);
|
||||
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);
|
||||
INIT_WORK(&lnk->link_down_wrk, smc_link_down_work);
|
||||
if (!ini->ib_dev->initialized) {
|
||||
@ -355,6 +738,7 @@ free_link_mem:
|
||||
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;
|
||||
@ -526,6 +910,14 @@ static int smc_switch_cursor(struct smc_sock *smc, struct smc_cdc_tx_pend *pend,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void smc_switch_link_and_count(struct smc_connection *conn,
|
||||
struct smc_link *to_lnk)
|
||||
{
|
||||
atomic_dec(&conn->lnk->conn_cnt);
|
||||
conn->lnk = to_lnk;
|
||||
atomic_inc(&conn->lnk->conn_cnt);
|
||||
}
|
||||
|
||||
struct smc_link *smc_switch_conns(struct smc_link_group *lgr,
|
||||
struct smc_link *from_lnk, bool is_dev_err)
|
||||
{
|
||||
@ -574,7 +966,7 @@ again:
|
||||
smc->sk.sk_state == SMC_PEERABORTWAIT ||
|
||||
smc->sk.sk_state == SMC_PROCESSABORT) {
|
||||
spin_lock_bh(&conn->send_lock);
|
||||
conn->lnk = to_lnk;
|
||||
smc_switch_link_and_count(conn, to_lnk);
|
||||
spin_unlock_bh(&conn->send_lock);
|
||||
continue;
|
||||
}
|
||||
@ -588,7 +980,7 @@ again:
|
||||
}
|
||||
/* avoid race with smcr_tx_sndbuf_nonempty() */
|
||||
spin_lock_bh(&conn->send_lock);
|
||||
conn->lnk = to_lnk;
|
||||
smc_switch_link_and_count(conn, to_lnk);
|
||||
rc = smc_switch_cursor(smc, pend, wr_buf);
|
||||
spin_unlock_bh(&conn->send_lock);
|
||||
sock_put(&smc->sk);
|
||||
@ -737,6 +1129,7 @@ void smcr_link_clear(struct smc_link *lnk, bool log)
|
||||
smc_ib_destroy_queue_pair(lnk);
|
||||
smc_ib_dealloc_protection_domain(lnk);
|
||||
smc_wr_free_link_mem(lnk);
|
||||
smc_ibdev_cnt_dec(lnk);
|
||||
put_device(&lnk->smcibdev->ibdev->dev);
|
||||
smcibdev = lnk->smcibdev;
|
||||
memset(lnk, 0, sizeof(struct smc_link));
|
||||
|
@ -13,7 +13,10 @@
|
||||
#define _SMC_CORE_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/smc.h>
|
||||
#include <linux/pci.h>
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "smc.h"
|
||||
#include "smc_ib.h"
|
||||
@ -124,11 +127,14 @@ struct smc_link {
|
||||
u8 link_is_asym; /* is link asymmetric? */
|
||||
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 */
|
||||
struct completion llc_testlink_resp; /* wait for rx of testlink */
|
||||
int llc_testlink_time; /* testlink interval */
|
||||
atomic_t conn_cnt; /* connections on this link */
|
||||
};
|
||||
|
||||
/* For now we just allow one parallel link per link group. The SMC protocol
|
||||
@ -363,6 +369,45 @@ 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_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;
|
||||
@ -410,6 +455,10 @@ 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);
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
@ -160,17 +147,17 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
|
||||
!list_empty(&smc->conn.lgr->list)) {
|
||||
struct smc_diag_lgrinfo linfo = {
|
||||
.role = smc->conn.lgr->role,
|
||||
.lnk[0].ibport = smc->conn.lgr->lnk[0].ibport,
|
||||
.lnk[0].link_id = smc->conn.lgr->lnk[0].link_id,
|
||||
.lnk[0].ibport = smc->conn.lnk->ibport,
|
||||
.lnk[0].link_id = smc->conn.lnk->link_id,
|
||||
};
|
||||
|
||||
memcpy(linfo.lnk[0].ibname,
|
||||
smc->conn.lgr->lnk[0].smcibdev->ibdev->name,
|
||||
sizeof(smc->conn.lgr->lnk[0].smcibdev->ibdev->name));
|
||||
sizeof(smc->conn.lnk->smcibdev->ibdev->name));
|
||||
smc_gid_be16_convert(linfo.lnk[0].gid,
|
||||
smc->conn.lgr->lnk[0].gid);
|
||||
smc->conn.lnk->gid);
|
||||
smc_gid_be16_convert(linfo.lnk[0].peer_gid,
|
||||
smc->conn.lgr->lnk[0].peer_gid);
|
||||
smc->conn.lnk->peer_gid);
|
||||
|
||||
if (nla_put(skb, SMC_DIAG_LGRINFO, sizeof(linfo), &linfo) < 0)
|
||||
goto errout;
|
||||
|
200
net/smc/smc_ib.c
200
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;
|
||||
@ -557,6 +713,49 @@ out:
|
||||
|
||||
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)
|
||||
{
|
||||
@ -596,6 +795,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,
|
||||
|
@ -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;
|
||||
@ -53,11 +54,15 @@ 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 */
|
||||
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);
|
||||
@ -87,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
|
||||
|
@ -15,13 +15,14 @@
|
||||
#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),
|
||||
.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 +52,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)
|
||||
{
|
||||
@ -201,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;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define SMCD_ISM_H
|
||||
|
||||
#include <linux/uio.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#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,7 @@ 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);
|
||||
int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
#endif
|
||||
|
85
net/smc/smc_netlink.c
Normal file
85
net/smc/smc_netlink.c
Normal file
@ -0,0 +1,85 @@
|
||||
// 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 <guvenc@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/smc.h>
|
||||
|
||||
#include "smc_core.h"
|
||||
#include "smc_ism.h"
|
||||
#include "smc_ib.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[] = {
|
||||
{
|
||||
.cmd = SMC_NETLINK_GET_SYS_INFO,
|
||||
/* 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,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_GET_LINK_SMCR,
|
||||
/* 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,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_GET_DEV_SMCD,
|
||||
/* 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] = {
|
||||
[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);
|
||||
}
|
32
net/smc/smc_netlink.h
Normal file
32
net/smc/smc_netlink.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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 <guvenc@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _SMC_NETLINK_H
|
||||
#define _SMC_NETLINK_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
@ -827,9 +827,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);
|
||||
|
Loading…
Reference in New Issue
Block a user