Commit 06f90dde authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents d31c0800 a3db10ef
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
@@ -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 */
+1 −1
Original line number Diff line number Diff line
@@ -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
+20 −19
Original line number Diff line number Diff line
@@ -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 @@ static int __init smc_init(void)
	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();
}
+5 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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
Loading