Blame view

net/smc/smc_diag.c 7.81 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
f16a7dd5c   Ursula Braun   smc: netlink inte...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * Shared Memory Communications over RDMA (SMC-R) and RoCE
   *
   * Monitoring SMC transport protocol sockets
   *
   * Copyright IBM Corp. 2016
   *
   * Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/init.h>
  #include <linux/sock_diag.h>
  #include <linux/inet_diag.h>
  #include <linux/smc_diag.h>
  #include <net/netlink.h>
  #include <net/smc.h>
  
  #include "smc.h"
  #include "smc_core.h"
8418cb406   Guvenc Gulce   net/smc: use the ...
24
25
26
27
28
29
30
31
  struct smc_diag_dump_ctx {
  	int pos[2];
  };
  
  static struct smc_diag_dump_ctx *smc_dump_context(struct netlink_callback *cb)
  {
  	return (struct smc_diag_dump_ctx *)cb->ctx;
  }
f16a7dd5c   Ursula Braun   smc: netlink inte...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  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);
457fed775   Eric Dumazet   net/smc: fix leak...
48
  	memset(r, 0, sizeof(*r));
232dc8ef6   Karsten Graul   net/smc: original...
49
  	r->diag_family = sk->sk_family;
457fed775   Eric Dumazet   net/smc: fix leak...
50
  	sock_diag_save_cookie(sk, r->id.idiag_cookie);
f16a7dd5c   Ursula Braun   smc: netlink inte...
51
52
53
54
55
  	if (!smc->clcsock)
  		return;
  	r->id.idiag_sport = htons(smc->clcsock->sk->sk_num);
  	r->id.idiag_dport = smc->clcsock->sk->sk_dport;
  	r->id.idiag_if = smc->clcsock->sk->sk_bound_dev_if;
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
56
  	if (sk->sk_protocol == SMCPROTO_SMC) {
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
57
58
59
60
  		r->id.idiag_src[0] = smc->clcsock->sk->sk_rcv_saddr;
  		r->id.idiag_dst[0] = smc->clcsock->sk->sk_daddr;
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (sk->sk_protocol == SMCPROTO_SMC6) {
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
61
62
63
64
65
66
  		memcpy(&r->id.idiag_src, &smc->clcsock->sk->sk_v6_rcv_saddr,
  		       sizeof(smc->clcsock->sk->sk_v6_rcv_saddr));
  		memcpy(&r->id.idiag_dst, &smc->clcsock->sk->sk_v6_daddr,
  		       sizeof(smc->clcsock->sk->sk_v6_daddr));
  #endif
  	}
f16a7dd5c   Ursula Braun   smc: netlink inte...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  }
  
  static int smc_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
  				   struct smc_diag_msg *r,
  				   struct user_namespace *user_ns)
  {
  	if (nla_put_u8(skb, SMC_DIAG_SHUTDOWN, sk->sk_shutdown))
  		return 1;
  
  	r->diag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
  	r->diag_inode = sock_i_ino(sk);
  	return 0;
  }
  
  static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
  			   struct netlink_callback *cb,
  			   const struct smc_diag_req *req,
  			   struct nlattr *bc)
  {
  	struct smc_sock *smc = smc_sk(sk);
603cc1498   Karsten Graul   net/smc: provide ...
87
  	struct smc_diag_fallback fallback;
f16a7dd5c   Ursula Braun   smc: netlink inte...
88
89
90
91
92
93
94
95
96
97
98
99
  	struct user_namespace *user_ns;
  	struct smc_diag_msg *r;
  	struct nlmsghdr *nlh;
  
  	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
  			cb->nlh->nlmsg_type, sizeof(*r), NLM_F_MULTI);
  	if (!nlh)
  		return -EMSGSIZE;
  
  	r = nlmsg_data(nlh);
  	smc_diag_msg_common_fill(r, sk);
  	r->diag_state = sk->sk_state;
c601171d7   Karsten Graul   net/smc: provide ...
100
101
102
103
104
105
  	if (smc->use_fallback)
  		r->diag_mode = SMC_DIAG_MODE_FALLBACK_TCP;
  	else if (smc->conn.lgr && smc->conn.lgr->is_smcd)
  		r->diag_mode = SMC_DIAG_MODE_SMCD;
  	else
  		r->diag_mode = SMC_DIAG_MODE_SMCR;
f16a7dd5c   Ursula Braun   smc: netlink inte...
106
107
108
  	user_ns = sk_user_ns(NETLINK_CB(cb->skb).sk);
  	if (smc_diag_msg_attrs_fill(sk, skb, r, user_ns))
  		goto errout;
603cc1498   Karsten Graul   net/smc: provide ...
109
110
111
112
  	fallback.reason = smc->fallback_rsn;
  	fallback.peer_diagnosis = smc->peer_diagnosis;
  	if (nla_put(skb, SMC_DIAG_FALLBACK, sizeof(fallback), &fallback) < 0)
  		goto errout;
1a0a04c7a   Ursula Braun   net/smc: check fo...
113
114
  	if ((req->diag_ext & (1 << (SMC_DIAG_CONNINFO - 1))) &&
  	    smc->conn.alert_token_local) {
f16a7dd5c   Ursula Braun   smc: netlink inte...
115
116
117
  		struct smc_connection *conn = &smc->conn;
  		struct smc_diag_conninfo cinfo = {
  			.token = conn->alert_token_local,
69cb7dc02   Hans Wippel   net/smc: add comm...
118
119
120
  			.sndbuf_size = conn->sndbuf_desc ?
  				conn->sndbuf_desc->len : 0,
  			.rmbe_size = conn->rmb_desc ? conn->rmb_desc->len : 0,
f16a7dd5c   Ursula Braun   smc: netlink inte...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  			.peer_rmbe_size = conn->peer_rmbe_size,
  
  			.rx_prod.wrap = conn->local_rx_ctrl.prod.wrap,
  			.rx_prod.count = conn->local_rx_ctrl.prod.count,
  			.rx_cons.wrap = conn->local_rx_ctrl.cons.wrap,
  			.rx_cons.count = conn->local_rx_ctrl.cons.count,
  
  			.tx_prod.wrap = conn->local_tx_ctrl.prod.wrap,
  			.tx_prod.count = conn->local_tx_ctrl.prod.count,
  			.tx_cons.wrap = conn->local_tx_ctrl.cons.wrap,
  			.tx_cons.count = conn->local_tx_ctrl.cons.count,
  
  			.tx_prod_flags =
  				*(u8 *)&conn->local_tx_ctrl.prod_flags,
  			.tx_conn_state_flags =
  				*(u8 *)&conn->local_tx_ctrl.conn_state_flags,
  			.rx_prod_flags = *(u8 *)&conn->local_rx_ctrl.prod_flags,
  			.rx_conn_state_flags =
  				*(u8 *)&conn->local_rx_ctrl.conn_state_flags,
  
  			.tx_prep.wrap = conn->tx_curs_prep.wrap,
  			.tx_prep.count = conn->tx_curs_prep.count,
  			.tx_sent.wrap = conn->tx_curs_sent.wrap,
  			.tx_sent.count = conn->tx_curs_sent.count,
  			.tx_fin.wrap = conn->tx_curs_fin.wrap,
  			.tx_fin.count = conn->tx_curs_fin.count,
  		};
  
  		if (nla_put(skb, SMC_DIAG_CONNINFO, sizeof(cinfo), &cinfo) < 0)
  			goto errout;
  	}
c6ba7c9ba   Hans Wippel   net/smc: add base...
152
153
  	if (smc->conn.lgr && !smc->conn.lgr->is_smcd &&
  	    (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
1a0a04c7a   Ursula Braun   net/smc: check fo...
154
  	    !list_empty(&smc->conn.lgr->list)) {
f16a7dd5c   Ursula Braun   smc: netlink inte...
155
156
157
158
159
160
161
162
163
164
  		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,
  		};
  
  		memcpy(linfo.lnk[0].ibname,
  		       smc->conn.lgr->lnk[0].smcibdev->ibdev->name,
  		       sizeof(smc->conn.lgr->lnk[0].smcibdev->ibdev->name));
  		smc_gid_be16_convert(linfo.lnk[0].gid,
7005ada68   Ursula Braun   net/smc: use corr...
165
  				     smc->conn.lgr->lnk[0].gid);
f16a7dd5c   Ursula Braun   smc: netlink inte...
166
167
168
169
170
171
  		smc_gid_be16_convert(linfo.lnk[0].peer_gid,
  				     smc->conn.lgr->lnk[0].peer_gid);
  
  		if (nla_put(skb, SMC_DIAG_LGRINFO, sizeof(linfo), &linfo) < 0)
  			goto errout;
  	}
4b1b7d3b3   Hans Wippel   net/smc: add SMC-...
172
173
174
175
  	if (smc->conn.lgr && smc->conn.lgr->is_smcd &&
  	    (req->diag_ext & (1 << (SMC_DIAG_DMBINFO - 1))) &&
  	    !list_empty(&smc->conn.lgr->list)) {
  		struct smc_connection *conn = &smc->conn;
ce51f63e6   Peilin Ye   net/smc: Prevent ...
176
177
178
179
180
181
182
183
184
  		struct smcd_diag_dmbinfo dinfo;
  
  		memset(&dinfo, 0, sizeof(dinfo));
  
  		dinfo.linkid = *((u32 *)conn->lgr->id);
  		dinfo.peer_gid = conn->lgr->peer_gid;
  		dinfo.my_gid = conn->lgr->smcd->local_gid;
  		dinfo.token = conn->rmb_desc->token;
  		dinfo.peer_token = conn->peer_token;
4b1b7d3b3   Hans Wippel   net/smc: add SMC-...
185
186
187
188
  
  		if (nla_put(skb, SMC_DIAG_DMBINFO, sizeof(dinfo), &dinfo) < 0)
  			goto errout;
  	}
f16a7dd5c   Ursula Braun   smc: netlink inte...
189
190
191
192
193
194
195
196
  
  	nlmsg_end(skb, nlh);
  	return 0;
  
  errout:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
197
  static int smc_diag_dump_proto(struct proto *prot, struct sk_buff *skb,
8418cb406   Guvenc Gulce   net/smc: use the ...
198
  			       struct netlink_callback *cb, int p_type)
f16a7dd5c   Ursula Braun   smc: netlink inte...
199
  {
8418cb406   Guvenc Gulce   net/smc: use the ...
200
  	struct smc_diag_dump_ctx *cb_ctx = smc_dump_context(cb);
f16a7dd5c   Ursula Braun   smc: netlink inte...
201
  	struct net *net = sock_net(skb->sk);
8418cb406   Guvenc Gulce   net/smc: use the ...
202
  	int snum = cb_ctx->pos[p_type];
f16a7dd5c   Ursula Braun   smc: netlink inte...
203
204
  	struct nlattr *bc = NULL;
  	struct hlist_head *head;
8418cb406   Guvenc Gulce   net/smc: use the ...
205
  	int rc = 0, num = 0;
f16a7dd5c   Ursula Braun   smc: netlink inte...
206
  	struct sock *sk;
f16a7dd5c   Ursula Braun   smc: netlink inte...
207

ed75986f4   Karsten Graul   net/smc: ipv6 sup...
208
209
  	read_lock(&prot->h.smc_hash->lock);
  	head = &prot->h.smc_hash->ht;
f16a7dd5c   Ursula Braun   smc: netlink inte...
210
211
212
213
214
215
  	if (hlist_empty(head))
  		goto out;
  
  	sk_for_each(sk, head) {
  		if (!net_eq(sock_net(sk), net))
  			continue;
8418cb406   Guvenc Gulce   net/smc: use the ...
216
217
  		if (num < snum)
  			goto next;
f16a7dd5c   Ursula Braun   smc: netlink inte...
218
  		rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc);
8418cb406   Guvenc Gulce   net/smc: use the ...
219
220
221
222
  		if (rc < 0)
  			goto out;
  next:
  		num++;
f16a7dd5c   Ursula Braun   smc: netlink inte...
223
224
225
  	}
  
  out:
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
226
  	read_unlock(&prot->h.smc_hash->lock);
8418cb406   Guvenc Gulce   net/smc: use the ...
227
  	cb_ctx->pos[p_type] = num;
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
228
229
230
231
232
233
  	return rc;
  }
  
  static int smc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	int rc = 0;
8418cb406   Guvenc Gulce   net/smc: use the ...
234
  	rc = smc_diag_dump_proto(&smc_proto, skb, cb, SMCPROTO_SMC);
ed75986f4   Karsten Graul   net/smc: ipv6 sup...
235
  	if (!rc)
8418cb406   Guvenc Gulce   net/smc: use the ...
236
237
  		smc_diag_dump_proto(&smc_proto6, skb, cb, SMCPROTO_SMC6);
  	return skb->len;
f16a7dd5c   Ursula Braun   smc: netlink inte...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  }
  
  static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
  {
  	struct net *net = sock_net(skb->sk);
  
  	if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY &&
  	    h->nlmsg_flags & NLM_F_DUMP) {
  		{
  			struct netlink_dump_control c = {
  				.dump = smc_diag_dump,
  				.min_dump_alloc = SKB_WITH_OVERHEAD(32768),
  			};
  			return netlink_dump_start(net->diag_nlsk, skb, h, &c);
  		}
  	}
  	return 0;
  }
  
  static const struct sock_diag_handler smc_diag_handler = {
  	.family = AF_SMC,
  	.dump = smc_diag_handler_dump,
  };
  
  static int __init smc_diag_init(void)
  {
  	return sock_diag_register(&smc_diag_handler);
  }
  
  static void __exit smc_diag_exit(void)
  {
  	sock_diag_unregister(&smc_diag_handler);
  }
  
  module_init(smc_diag_init);
  module_exit(smc_diag_exit);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 43 /* AF_SMC */);