Commit 220e898d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-smc-stats'



Karsten Graul says:

====================
net/smc: Add SMC statistic support

Please apply the following patch series for smc to netdev's net-next tree.

This v2 is a resend of the code contained in v1 but with an updated
cover letter to describe why we have chosen to use the generic netlink
mechanism to access the smc protocol's statistic data.

The patchset adds statistic support to the SMC protocol. Per-cpu
variables are used to collect the statistic information for better
performance and for reducing concurrency pitfalls. The code that is
collecting statistic data is implemented in macros to increase code
reuse and readability.
The generic netlink mechanism in SMC is extended to provide the
collected statistics to userspace.
Network namespace awareness is also part of the statistics
implementation.

SMC is a protocol interacting with PCI devices (like RoCE Cards) and
runs on top of the TCP protocol. As SMC is a network protocol and not
an ethernet device driver, we decided to use the generic netlink
interface. This should be comparable to what other protocols in the
net subsystem like tipc, ncsi, ieee802154 or tcp, et al, do.
There is already an established internal generic netlink interface
mechanism in SMC which is used to collect SMC Protocol internal
information. This patchset extends that existing mechanism.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fb0a1dac 194730a9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <net/netns/mpls.h>
#include <net/netns/can.h>
#include <net/netns/xdp.h>
#include <net/netns/smc.h>
#include <net/netns/bpf.h>
#include <linux/ns_common.h>
#include <linux/idr.h>
@@ -170,6 +171,9 @@ struct net {
	struct sock		*crypto_nlsk;
#endif
	struct sock		*diag_nlsk;
#if IS_ENABLED(CONFIG_SMC)
	struct netns_smc	smc;
#endif
} __randomize_layout;

#include <linux/seq_file_net.h>
+16 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NETNS_SMC_H__
#define __NETNS_SMC_H__
#include <linux/mutex.h>
#include <linux/percpu.h>

struct smc_stats_rsn;
struct smc_stats;
struct netns_smc {
	/* per cpu counters for SMC */
	struct smc_stats __percpu	*smc_stats;
	/* protect fback_rsn */
	struct mutex			mutex_fback_rsn;
	struct smc_stats_rsn		*fback_rsn;
};
#endif
+83 −0
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ enum {
	SMC_NETLINK_GET_LGR_SMCD,
	SMC_NETLINK_GET_DEV_SMCD,
	SMC_NETLINK_GET_DEV_SMCR,
	SMC_NETLINK_GET_STATS,
	SMC_NETLINK_GET_FBACK_STATS,
};

/* SMC_GENL_FAMILY top level attributes */
@@ -58,6 +60,8 @@ enum {
	SMC_GEN_LGR_SMCD,		/* nest */
	SMC_GEN_DEV_SMCD,		/* nest */
	SMC_GEN_DEV_SMCR,		/* nest */
	SMC_GEN_STATS,			/* nest */
	SMC_GEN_FBACK_STATS,		/* nest */
	__SMC_GEN_MAX,
	SMC_GEN_MAX = __SMC_GEN_MAX - 1
};
@@ -159,4 +163,83 @@ enum {
	SMC_NLA_DEV_MAX = __SMC_NLA_DEV_MAX - 1
};

/* SMC_NLA_STATS_T_TX(RX)_RMB_SIZE nested attributes */
/* SMC_NLA_STATS_TX(RX)PLOAD_SIZE nested attributes */
enum {
	SMC_NLA_STATS_PLOAD_PAD,
	SMC_NLA_STATS_PLOAD_8K,		/* u64 */
	SMC_NLA_STATS_PLOAD_16K,	/* u64 */
	SMC_NLA_STATS_PLOAD_32K,	/* u64 */
	SMC_NLA_STATS_PLOAD_64K,	/* u64 */
	SMC_NLA_STATS_PLOAD_128K,	/* u64 */
	SMC_NLA_STATS_PLOAD_256K,	/* u64 */
	SMC_NLA_STATS_PLOAD_512K,	/* u64 */
	SMC_NLA_STATS_PLOAD_1024K,	/* u64 */
	SMC_NLA_STATS_PLOAD_G_1024K,	/* u64 */
	__SMC_NLA_STATS_PLOAD_MAX,
	SMC_NLA_STATS_PLOAD_MAX = __SMC_NLA_STATS_PLOAD_MAX - 1
};

/* SMC_NLA_STATS_T_TX(RX)_RMB_STATS nested attributes */
enum {
	SMC_NLA_STATS_RMB_PAD,
	SMC_NLA_STATS_RMB_SIZE_SM_PEER_CNT,	/* u64 */
	SMC_NLA_STATS_RMB_SIZE_SM_CNT,		/* u64 */
	SMC_NLA_STATS_RMB_FULL_PEER_CNT,	/* u64 */
	SMC_NLA_STATS_RMB_FULL_CNT,		/* u64 */
	SMC_NLA_STATS_RMB_REUSE_CNT,		/* u64 */
	SMC_NLA_STATS_RMB_ALLOC_CNT,		/* u64 */
	SMC_NLA_STATS_RMB_DGRADE_CNT,		/* u64 */
	__SMC_NLA_STATS_RMB_MAX,
	SMC_NLA_STATS_RMB_MAX = __SMC_NLA_STATS_RMB_MAX - 1
};

/* SMC_NLA_STATS_SMCD_TECH and _SMCR_TECH nested attributes */
enum {
	SMC_NLA_STATS_T_PAD,
	SMC_NLA_STATS_T_TX_RMB_SIZE,	/* nest */
	SMC_NLA_STATS_T_RX_RMB_SIZE,	/* nest */
	SMC_NLA_STATS_T_TXPLOAD_SIZE,	/* nest */
	SMC_NLA_STATS_T_RXPLOAD_SIZE,	/* nest */
	SMC_NLA_STATS_T_TX_RMB_STATS,	/* nest */
	SMC_NLA_STATS_T_RX_RMB_STATS,	/* nest */
	SMC_NLA_STATS_T_CLNT_V1_SUCC,	/* u64 */
	SMC_NLA_STATS_T_CLNT_V2_SUCC,	/* u64 */
	SMC_NLA_STATS_T_SRV_V1_SUCC,	/* u64 */
	SMC_NLA_STATS_T_SRV_V2_SUCC,	/* u64 */
	SMC_NLA_STATS_T_SENDPAGE_CNT,	/* u64 */
	SMC_NLA_STATS_T_SPLICE_CNT,	/* u64 */
	SMC_NLA_STATS_T_CORK_CNT,	/* u64 */
	SMC_NLA_STATS_T_NDLY_CNT,	/* u64 */
	SMC_NLA_STATS_T_URG_DATA_CNT,	/* u64 */
	SMC_NLA_STATS_T_RX_BYTES,	/* u64 */
	SMC_NLA_STATS_T_TX_BYTES,	/* u64 */
	SMC_NLA_STATS_T_RX_CNT,		/* u64 */
	SMC_NLA_STATS_T_TX_CNT,		/* u64 */
	__SMC_NLA_STATS_T_MAX,
	SMC_NLA_STATS_T_MAX = __SMC_NLA_STATS_T_MAX - 1
};

/* SMC_GEN_STATS attributes */
enum {
	SMC_NLA_STATS_PAD,
	SMC_NLA_STATS_SMCD_TECH,	/* nest */
	SMC_NLA_STATS_SMCR_TECH,	/* nest */
	SMC_NLA_STATS_CLNT_HS_ERR_CNT,	/* u64 */
	SMC_NLA_STATS_SRV_HS_ERR_CNT,	/* u64 */
	__SMC_NLA_STATS_MAX,
	SMC_NLA_STATS_MAX = __SMC_NLA_STATS_MAX - 1
};

/* SMC_GEN_FBACK_STATS attributes */
enum {
	SMC_NLA_FBACK_STATS_PAD,
	SMC_NLA_FBACK_STATS_TYPE,	/* u8 */
	SMC_NLA_FBACK_STATS_SRV_CNT,	/* u64 */
	SMC_NLA_FBACK_STATS_CLNT_CNT,	/* u64 */
	SMC_NLA_FBACK_STATS_RSN_CODE,	/* u32 */
	SMC_NLA_FBACK_STATS_RSN_CNT,	/* u16 */
	__SMC_NLA_FBACK_STATS_MAX,
	SMC_NLA_FBACK_STATS_MAX = __SMC_NLA_FBACK_STATS_MAX - 1
};
#endif /* _UAPI_LINUX_SMC_H */
+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_netlink.o
smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o
+85 −17
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include "smc_tx.h"
#include "smc_rx.h"
#include "smc_close.h"
#include "smc_stats.h"

static DEFINE_MUTEX(smc_server_lgr_pending);	/* serialize link group
						 * creation on server
@@ -508,9 +509,44 @@ static void smc_link_save_peer_info(struct smc_link *link,
	link->peer_mtu = clc->r0.qp_mtu;
}

static void smc_switch_to_fallback(struct smc_sock *smc)
static void smc_stat_inc_fback_rsn_cnt(struct smc_sock *smc,
				       struct smc_stats_fback *fback_arr)
{
	int cnt;

	for (cnt = 0; cnt < SMC_MAX_FBACK_RSN_CNT; cnt++) {
		if (fback_arr[cnt].fback_code == smc->fallback_rsn) {
			fback_arr[cnt].count++;
			break;
		}
		if (!fback_arr[cnt].fback_code) {
			fback_arr[cnt].fback_code = smc->fallback_rsn;
			fback_arr[cnt].count++;
			break;
		}
	}
}

static void smc_stat_fallback(struct smc_sock *smc)
{
	struct net *net = sock_net(&smc->sk);

	mutex_lock(&net->smc.mutex_fback_rsn);
	if (smc->listen_smc) {
		smc_stat_inc_fback_rsn_cnt(smc, net->smc.fback_rsn->srv);
		net->smc.fback_rsn->srv_fback_cnt++;
	} else {
		smc_stat_inc_fback_rsn_cnt(smc, net->smc.fback_rsn->clnt);
		net->smc.fback_rsn->clnt_fback_cnt++;
	}
	mutex_unlock(&net->smc.mutex_fback_rsn);
}

static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
{
	smc->use_fallback = true;
	smc->fallback_rsn = reason_code;
	smc_stat_fallback(smc);
	if (smc->sk.sk_socket && smc->sk.sk_socket->file) {
		smc->clcsock->file = smc->sk.sk_socket->file;
		smc->clcsock->file->private_data = smc->clcsock;
@@ -522,8 +558,7 @@ static void smc_switch_to_fallback(struct smc_sock *smc)
/* fall back during connect */
static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
{
	smc_switch_to_fallback(smc);
	smc->fallback_rsn = reason_code;
	smc_switch_to_fallback(smc, reason_code);
	smc_copy_sock_settings_to_clc(smc);
	smc->connect_nonblock = 0;
	if (smc->sk.sk_state == SMC_INIT)
@@ -535,9 +570,11 @@ static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code,
					u8 version)
{
	struct net *net = sock_net(&smc->sk);
	int rc;

	if (reason_code < 0) { /* error, fallback is not possible */
		this_cpu_inc(net->smc.smc_stats->clnt_hshake_err_cnt);
		if (smc->sk.sk_state == SMC_INIT)
			sock_put(&smc->sk); /* passive closing */
		return reason_code;
@@ -545,6 +582,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code,
	if (reason_code != SMC_CLC_DECL_PEERDECL) {
		rc = smc_clc_send_decline(smc, reason_code, version);
		if (rc < 0) {
			this_cpu_inc(net->smc.smc_stats->clnt_hshake_err_cnt);
			if (smc->sk.sk_state == SMC_INIT)
				sock_put(&smc->sk); /* passive closing */
			return rc;
@@ -992,6 +1030,7 @@ static int __smc_connect(struct smc_sock *smc)
	if (rc)
		goto vlan_cleanup;

	SMC_STAT_CLNT_SUCC_INC(sock_net(smc->clcsock->sk), aclc);
	smc_connect_ism_vlan_cleanup(smc, ini);
	kfree(buf);
	kfree(ini);
@@ -1307,7 +1346,9 @@ static void smc_listen_out_connected(struct smc_sock *new_smc)
static void smc_listen_out_err(struct smc_sock *new_smc)
{
	struct sock *newsmcsk = &new_smc->sk;
	struct net *net = sock_net(newsmcsk);

	this_cpu_inc(net->smc.smc_stats->srv_hshake_err_cnt);
	if (newsmcsk->sk_state == SMC_INIT)
		sock_put(&new_smc->sk); /* passive closing */
	newsmcsk->sk_state = SMC_CLOSED;
@@ -1325,8 +1366,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
		smc_listen_out_err(new_smc);
		return;
	}
	smc_switch_to_fallback(new_smc);
	new_smc->fallback_rsn = reason_code;
	smc_switch_to_fallback(new_smc, reason_code);
	if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
		if (smc_clc_send_decline(new_smc, reason_code, version) < 0) {
			smc_listen_out_err(new_smc);
@@ -1699,8 +1739,7 @@ static void smc_listen_work(struct work_struct *work)

	/* check if peer is smc capable */
	if (!tcp_sk(newclcsock->sk)->syn_smc) {
		smc_switch_to_fallback(new_smc);
		new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC;
		smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC);
		smc_listen_out_connected(new_smc);
		return;
	}
@@ -1778,6 +1817,7 @@ static void smc_listen_work(struct work_struct *work)
	}
	smc_conn_save_peer_info(new_smc, cclc);
	smc_listen_out_connected(new_smc);
	SMC_STAT_SERV_SUCC_INC(sock_net(newclcsock->sk), ini);
	goto out_free;

out_unlock:
@@ -1984,18 +2024,19 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)

	if (msg->msg_flags & MSG_FASTOPEN) {
		if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
			smc_switch_to_fallback(smc);
			smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
			smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
		} else {
			rc = -EINVAL;
			goto out;
		}
	}

	if (smc->use_fallback)
	if (smc->use_fallback) {
		rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len);
	else
	} else {
		rc = smc_tx_sendmsg(smc, msg, len);
		SMC_STAT_TX_PAYLOAD(smc, len, rc);
	}
out:
	release_sock(sk);
	return rc;
@@ -2030,6 +2071,7 @@ static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
	} else {
		msg->msg_namelen = 0;
		rc = smc_rx_recvmsg(smc, msg, NULL, len, flags);
		SMC_STAT_RX_PAYLOAD(smc, rc, rc);
	}

out:
@@ -2194,8 +2236,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
	case TCP_FASTOPEN_NO_COOKIE:
		/* option not supported by SMC */
		if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
			smc_switch_to_fallback(smc);
			smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
			smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
		} else {
			rc = -EINVAL;
		}
@@ -2204,19 +2245,23 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
		if (sk->sk_state != SMC_INIT &&
		    sk->sk_state != SMC_LISTEN &&
		    sk->sk_state != SMC_CLOSED) {
			if (val)
			if (val) {
				SMC_STAT_INC(smc, ndly_cnt);
				mod_delayed_work(smc->conn.lgr->tx_wq,
						 &smc->conn.tx_work, 0);
			}
		}
		break;
	case TCP_CORK:
		if (sk->sk_state != SMC_INIT &&
		    sk->sk_state != SMC_LISTEN &&
		    sk->sk_state != SMC_CLOSED) {
			if (!val)
			if (!val) {
				SMC_STAT_INC(smc, cork_cnt);
				mod_delayed_work(smc->conn.lgr->tx_wq,
						 &smc->conn.tx_work, 0);
			}
		}
		break;
	case TCP_DEFER_ACCEPT:
		smc->sockopt_defer_accept = val;
@@ -2338,11 +2383,13 @@ static ssize_t smc_sendpage(struct socket *sock, struct page *page,
		goto out;
	}
	release_sock(sk);
	if (smc->use_fallback)
	if (smc->use_fallback) {
		rc = kernel_sendpage(smc->clcsock, page, offset,
				     size, flags);
	else
	} else {
		SMC_STAT_INC(smc, sendpage_cnt);
		rc = sock_no_sendpage(sock, page, offset, size, flags);
	}

out:
	return rc;
@@ -2391,6 +2438,7 @@ static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos,
			flags = MSG_DONTWAIT;
		else
			flags = 0;
		SMC_STAT_INC(smc, splice_cnt);
		rc = smc_rx_recvmsg(smc, NULL, pipe, len, flags);
	}
out:
@@ -2479,6 +2527,16 @@ static void __net_exit smc_net_exit(struct net *net)
	smc_pnet_net_exit(net);
}

static __net_init int smc_net_stat_init(struct net *net)
{
	return smc_stats_init(net);
}

static void __net_exit smc_net_stat_exit(struct net *net)
{
	smc_stats_exit(net);
}

static struct pernet_operations smc_net_ops = {
	.init = smc_net_init,
	.exit = smc_net_exit,
@@ -2486,6 +2544,11 @@ static struct pernet_operations smc_net_ops = {
	.size = sizeof(struct smc_net),
};

static struct pernet_operations smc_net_stat_ops = {
	.init = smc_net_stat_init,
	.exit = smc_net_stat_exit,
};

static int __init smc_init(void)
{
	int rc;
@@ -2494,6 +2557,10 @@ static int __init smc_init(void)
	if (rc)
		return rc;

	rc = register_pernet_subsys(&smc_net_stat_ops);
	if (rc)
		return rc;

	smc_ism_init();
	smc_clc_init();

@@ -2595,6 +2662,7 @@ static void __exit smc_exit(void)
	proto_unregister(&smc_proto);
	smc_pnet_exit();
	smc_nl_exit();
	unregister_pernet_subsys(&smc_net_stat_ops);
	unregister_pernet_subsys(&smc_net_ops);
	rcu_barrier();
}
Loading