1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved.
6 * Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved.
7 * Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved.
10 #define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt
16 #define MIN_MAX_RECONN_ATT -1
17 #define MAX_MAX_RECONN_ATT 9999
19 static void rtrs_clt_sess_release(struct kobject
*kobj
)
21 struct rtrs_clt_sess
*sess
;
23 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
28 static struct kobj_type ktype_sess
= {
29 .sysfs_ops
= &kobj_sysfs_ops
,
30 .release
= rtrs_clt_sess_release
33 static void rtrs_clt_sess_stats_release(struct kobject
*kobj
)
35 struct rtrs_clt_stats
*stats
;
37 stats
= container_of(kobj
, struct rtrs_clt_stats
, kobj_stats
);
39 free_percpu(stats
->pcpu_stats
);
44 static struct kobj_type ktype_stats
= {
45 .sysfs_ops
= &kobj_sysfs_ops
,
46 .release
= rtrs_clt_sess_stats_release
,
49 static ssize_t
max_reconnect_attempts_show(struct device
*dev
,
50 struct device_attribute
*attr
,
53 struct rtrs_clt
*clt
= container_of(dev
, struct rtrs_clt
, dev
);
55 return sysfs_emit(page
, "%d\n",
56 rtrs_clt_get_max_reconnect_attempts(clt
));
59 static ssize_t
max_reconnect_attempts_store(struct device
*dev
,
60 struct device_attribute
*attr
,
66 struct rtrs_clt
*clt
= container_of(dev
, struct rtrs_clt
, dev
);
68 ret
= kstrtoint(buf
, 10, &value
);
70 rtrs_err(clt
, "%s: failed to convert string '%s' to int\n",
71 attr
->attr
.name
, buf
);
74 if (value
> MAX_MAX_RECONN_ATT
||
75 value
< MIN_MAX_RECONN_ATT
) {
77 "%s: invalid range (provided: '%s', accepted: min: %d, max: %d)\n",
78 attr
->attr
.name
, buf
, MIN_MAX_RECONN_ATT
,
82 rtrs_clt_set_max_reconnect_attempts(clt
, value
);
87 static DEVICE_ATTR_RW(max_reconnect_attempts
);
89 static ssize_t
mpath_policy_show(struct device
*dev
,
90 struct device_attribute
*attr
,
95 clt
= container_of(dev
, struct rtrs_clt
, dev
);
97 switch (clt
->mp_policy
) {
99 return sysfs_emit(page
, "round-robin (RR: %d)\n",
101 case MP_POLICY_MIN_INFLIGHT
:
102 return sysfs_emit(page
, "min-inflight (MI: %d)\n",
105 return sysfs_emit(page
, "Unknown (%d)\n", clt
->mp_policy
);
109 static ssize_t
mpath_policy_store(struct device
*dev
,
110 struct device_attribute
*attr
,
114 struct rtrs_clt
*clt
;
118 clt
= container_of(dev
, struct rtrs_clt
, dev
);
120 ret
= kstrtoint(buf
, 10, &value
);
121 if (!ret
&& (value
== MP_POLICY_RR
||
122 value
== MP_POLICY_MIN_INFLIGHT
)) {
123 clt
->mp_policy
= value
;
127 if (!strncasecmp(buf
, "round-robin", 11) ||
128 !strncasecmp(buf
, "rr", 2))
129 clt
->mp_policy
= MP_POLICY_RR
;
130 else if (!strncasecmp(buf
, "min-inflight", 12) ||
131 !strncasecmp(buf
, "mi", 2))
132 clt
->mp_policy
= MP_POLICY_MIN_INFLIGHT
;
139 static DEVICE_ATTR_RW(mpath_policy
);
141 static ssize_t
add_path_show(struct device
*dev
,
142 struct device_attribute
*attr
, char *page
)
146 "Usage: echo [<source addr>@]<destination addr> > %s\n\n*addr ::= [ ip:<ipv4|ipv6> | gid:<gid> ]\n",
150 static ssize_t
add_path_store(struct device
*dev
,
151 struct device_attribute
*attr
,
152 const char *buf
, size_t count
)
154 struct sockaddr_storage srcaddr
, dstaddr
;
155 struct rtrs_addr addr
= {
159 struct rtrs_clt
*clt
;
164 clt
= container_of(dev
, struct rtrs_clt
, dev
);
166 nl
= strchr(buf
, '\n');
171 err
= rtrs_addr_to_sockaddr(buf
, len
, clt
->port
, &addr
);
175 err
= rtrs_clt_create_path_from_sysfs(clt
, &addr
);
182 static DEVICE_ATTR_RW(add_path
);
184 static ssize_t
rtrs_clt_state_show(struct kobject
*kobj
,
185 struct kobj_attribute
*attr
, char *page
)
187 struct rtrs_clt_sess
*sess
;
189 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
190 if (sess
->state
== RTRS_CLT_CONNECTED
)
191 return sysfs_emit(page
, "connected\n");
193 return sysfs_emit(page
, "disconnected\n");
196 static struct kobj_attribute rtrs_clt_state_attr
=
197 __ATTR(state
, 0444, rtrs_clt_state_show
, NULL
);
199 static ssize_t
rtrs_clt_reconnect_show(struct kobject
*kobj
,
200 struct kobj_attribute
*attr
, char *buf
)
202 return sysfs_emit(buf
, "Usage: echo 1 > %s\n", attr
->attr
.name
);
205 static ssize_t
rtrs_clt_reconnect_store(struct kobject
*kobj
,
206 struct kobj_attribute
*attr
,
207 const char *buf
, size_t count
)
209 struct rtrs_clt_sess
*sess
;
212 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
213 if (!sysfs_streq(buf
, "1")) {
214 rtrs_err(sess
->clt
, "%s: unknown value: '%s'\n",
215 attr
->attr
.name
, buf
);
218 ret
= rtrs_clt_reconnect_from_sysfs(sess
);
225 static struct kobj_attribute rtrs_clt_reconnect_attr
=
226 __ATTR(reconnect
, 0644, rtrs_clt_reconnect_show
,
227 rtrs_clt_reconnect_store
);
229 static ssize_t
rtrs_clt_disconnect_show(struct kobject
*kobj
,
230 struct kobj_attribute
*attr
, char *buf
)
232 return sysfs_emit(buf
, "Usage: echo 1 > %s\n", attr
->attr
.name
);
235 static ssize_t
rtrs_clt_disconnect_store(struct kobject
*kobj
,
236 struct kobj_attribute
*attr
,
237 const char *buf
, size_t count
)
239 struct rtrs_clt_sess
*sess
;
242 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
243 if (!sysfs_streq(buf
, "1")) {
244 rtrs_err(sess
->clt
, "%s: unknown value: '%s'\n",
245 attr
->attr
.name
, buf
);
248 ret
= rtrs_clt_disconnect_from_sysfs(sess
);
255 static struct kobj_attribute rtrs_clt_disconnect_attr
=
256 __ATTR(disconnect
, 0644, rtrs_clt_disconnect_show
,
257 rtrs_clt_disconnect_store
);
259 static ssize_t
rtrs_clt_remove_path_show(struct kobject
*kobj
,
260 struct kobj_attribute
*attr
, char *buf
)
262 return sysfs_emit(buf
, "Usage: echo 1 > %s\n", attr
->attr
.name
);
265 static ssize_t
rtrs_clt_remove_path_store(struct kobject
*kobj
,
266 struct kobj_attribute
*attr
,
267 const char *buf
, size_t count
)
269 struct rtrs_clt_sess
*sess
;
272 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
273 if (!sysfs_streq(buf
, "1")) {
274 rtrs_err(sess
->clt
, "%s: unknown value: '%s'\n",
275 attr
->attr
.name
, buf
);
278 ret
= rtrs_clt_remove_path_from_sysfs(sess
, &attr
->attr
);
285 static struct kobj_attribute rtrs_clt_remove_path_attr
=
286 __ATTR(remove_path
, 0644, rtrs_clt_remove_path_show
,
287 rtrs_clt_remove_path_store
);
289 STAT_ATTR(struct rtrs_clt_stats
, cpu_migration
,
290 rtrs_clt_stats_migration_cnt_to_str
,
291 rtrs_clt_reset_cpu_migr_stats
);
293 STAT_ATTR(struct rtrs_clt_stats
, reconnects
,
294 rtrs_clt_stats_reconnects_to_str
,
295 rtrs_clt_reset_reconnects_stat
);
297 STAT_ATTR(struct rtrs_clt_stats
, rdma
,
298 rtrs_clt_stats_rdma_to_str
,
299 rtrs_clt_reset_rdma_stats
);
301 STAT_ATTR(struct rtrs_clt_stats
, reset_all
,
302 rtrs_clt_reset_all_help
,
303 rtrs_clt_reset_all_stats
);
305 static struct attribute
*rtrs_clt_stats_attrs
[] = {
306 &cpu_migration_attr
.attr
,
307 &reconnects_attr
.attr
,
309 &reset_all_attr
.attr
,
313 static const struct attribute_group rtrs_clt_stats_attr_group
= {
314 .attrs
= rtrs_clt_stats_attrs
,
317 static ssize_t
rtrs_clt_hca_port_show(struct kobject
*kobj
,
318 struct kobj_attribute
*attr
,
321 struct rtrs_clt_sess
*sess
;
323 sess
= container_of(kobj
, typeof(*sess
), kobj
);
325 return sysfs_emit(page
, "%u\n", sess
->hca_port
);
328 static struct kobj_attribute rtrs_clt_hca_port_attr
=
329 __ATTR(hca_port
, 0444, rtrs_clt_hca_port_show
, NULL
);
331 static ssize_t
rtrs_clt_hca_name_show(struct kobject
*kobj
,
332 struct kobj_attribute
*attr
,
335 struct rtrs_clt_sess
*sess
;
337 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
339 return sysfs_emit(page
, "%s\n", sess
->hca_name
);
342 static struct kobj_attribute rtrs_clt_hca_name_attr
=
343 __ATTR(hca_name
, 0444, rtrs_clt_hca_name_show
, NULL
);
345 static ssize_t
rtrs_clt_src_addr_show(struct kobject
*kobj
,
346 struct kobj_attribute
*attr
,
349 struct rtrs_clt_sess
*sess
;
352 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
353 len
= sockaddr_to_str((struct sockaddr
*)&sess
->s
.src_addr
, page
,
355 len
+= sysfs_emit_at(page
, len
, "\n");
359 static struct kobj_attribute rtrs_clt_src_addr_attr
=
360 __ATTR(src_addr
, 0444, rtrs_clt_src_addr_show
, NULL
);
362 static ssize_t
rtrs_clt_dst_addr_show(struct kobject
*kobj
,
363 struct kobj_attribute
*attr
,
366 struct rtrs_clt_sess
*sess
;
369 sess
= container_of(kobj
, struct rtrs_clt_sess
, kobj
);
370 len
= sockaddr_to_str((struct sockaddr
*)&sess
->s
.dst_addr
, page
,
372 len
+= sysfs_emit_at(page
, len
, "\n");
376 static struct kobj_attribute rtrs_clt_dst_addr_attr
=
377 __ATTR(dst_addr
, 0444, rtrs_clt_dst_addr_show
, NULL
);
379 static struct attribute
*rtrs_clt_sess_attrs
[] = {
380 &rtrs_clt_hca_name_attr
.attr
,
381 &rtrs_clt_hca_port_attr
.attr
,
382 &rtrs_clt_src_addr_attr
.attr
,
383 &rtrs_clt_dst_addr_attr
.attr
,
384 &rtrs_clt_state_attr
.attr
,
385 &rtrs_clt_reconnect_attr
.attr
,
386 &rtrs_clt_disconnect_attr
.attr
,
387 &rtrs_clt_remove_path_attr
.attr
,
391 static const struct attribute_group rtrs_clt_sess_attr_group
= {
392 .attrs
= rtrs_clt_sess_attrs
,
395 int rtrs_clt_create_sess_files(struct rtrs_clt_sess
*sess
)
397 struct rtrs_clt
*clt
= sess
->clt
;
401 cnt
= sockaddr_to_str((struct sockaddr
*)&sess
->s
.src_addr
,
403 cnt
+= scnprintf(str
+ cnt
, sizeof(str
) - cnt
, "@");
404 sockaddr_to_str((struct sockaddr
*)&sess
->s
.dst_addr
,
405 str
+ cnt
, sizeof(str
) - cnt
);
407 err
= kobject_init_and_add(&sess
->kobj
, &ktype_sess
, clt
->kobj_paths
,
410 pr_err("kobject_init_and_add: %d\n", err
);
413 err
= sysfs_create_group(&sess
->kobj
, &rtrs_clt_sess_attr_group
);
415 pr_err("sysfs_create_group(): %d\n", err
);
418 err
= kobject_init_and_add(&sess
->stats
->kobj_stats
, &ktype_stats
,
419 &sess
->kobj
, "stats");
421 pr_err("kobject_init_and_add: %d\n", err
);
425 err
= sysfs_create_group(&sess
->stats
->kobj_stats
,
426 &rtrs_clt_stats_attr_group
);
428 pr_err("failed to create stats sysfs group, err: %d\n", err
);
435 kobject_del(&sess
->stats
->kobj_stats
);
436 kobject_put(&sess
->stats
->kobj_stats
);
438 sysfs_remove_group(&sess
->kobj
, &rtrs_clt_sess_attr_group
);
440 kobject_del(&sess
->kobj
);
441 kobject_put(&sess
->kobj
);
446 void rtrs_clt_destroy_sess_files(struct rtrs_clt_sess
*sess
,
447 const struct attribute
*sysfs_self
)
449 kobject_del(&sess
->stats
->kobj_stats
);
450 kobject_put(&sess
->stats
->kobj_stats
);
452 sysfs_remove_file_self(&sess
->kobj
, sysfs_self
);
453 kobject_del(&sess
->kobj
);
456 static struct attribute
*rtrs_clt_attrs
[] = {
457 &dev_attr_max_reconnect_attempts
.attr
,
458 &dev_attr_mpath_policy
.attr
,
459 &dev_attr_add_path
.attr
,
463 static const struct attribute_group rtrs_clt_attr_group
= {
464 .attrs
= rtrs_clt_attrs
,
467 int rtrs_clt_create_sysfs_root_files(struct rtrs_clt
*clt
)
469 return sysfs_create_group(&clt
->dev
.kobj
, &rtrs_clt_attr_group
);
472 void rtrs_clt_destroy_sysfs_root_folders(struct rtrs_clt
*clt
)
474 if (clt
->kobj_paths
) {
475 kobject_del(clt
->kobj_paths
);
476 kobject_put(clt
->kobj_paths
);
480 void rtrs_clt_destroy_sysfs_root_files(struct rtrs_clt
*clt
)
482 sysfs_remove_group(&clt
->dev
.kobj
, &rtrs_clt_attr_group
);