Mention branches and keyring.
[releases.git] / rtrs / rtrs-clt-sysfs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * RDMA Transport Layer
4  *
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.
8  */
9 #undef pr_fmt
10 #define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt
11
12 #include "rtrs-pri.h"
13 #include "rtrs-clt.h"
14 #include "rtrs-log.h"
15
16 #define MIN_MAX_RECONN_ATT -1
17 #define MAX_MAX_RECONN_ATT 9999
18
19 static void rtrs_clt_path_release(struct kobject *kobj)
20 {
21         struct rtrs_clt_path *clt_path;
22
23         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
24
25         free_path(clt_path);
26 }
27
28 static struct kobj_type ktype_sess = {
29         .sysfs_ops = &kobj_sysfs_ops,
30         .release = rtrs_clt_path_release
31 };
32
33 static void rtrs_clt_path_stats_release(struct kobject *kobj)
34 {
35         struct rtrs_clt_stats *stats;
36
37         stats = container_of(kobj, struct rtrs_clt_stats, kobj_stats);
38
39         free_percpu(stats->pcpu_stats);
40
41         kfree(stats);
42 }
43
44 static struct kobj_type ktype_stats = {
45         .sysfs_ops = &kobj_sysfs_ops,
46         .release = rtrs_clt_path_stats_release,
47 };
48
49 static ssize_t max_reconnect_attempts_show(struct device *dev,
50                                            struct device_attribute *attr,
51                                            char *page)
52 {
53         struct rtrs_clt_sess *clt = container_of(dev, struct rtrs_clt_sess,
54                                                  dev);
55
56         return sysfs_emit(page, "%d\n",
57                           rtrs_clt_get_max_reconnect_attempts(clt));
58 }
59
60 static ssize_t max_reconnect_attempts_store(struct device *dev,
61                                             struct device_attribute *attr,
62                                             const char *buf,
63                                             size_t count)
64 {
65         int value;
66         int ret;
67         struct rtrs_clt_sess *clt  = container_of(dev, struct rtrs_clt_sess,
68                                                   dev);
69
70         ret = kstrtoint(buf, 10, &value);
71         if (ret) {
72                 rtrs_err(clt, "%s: failed to convert string '%s' to int\n",
73                           attr->attr.name, buf);
74                 return ret;
75         }
76         if (value > MAX_MAX_RECONN_ATT ||
77                      value < MIN_MAX_RECONN_ATT) {
78                 rtrs_err(clt,
79                           "%s: invalid range (provided: '%s', accepted: min: %d, max: %d)\n",
80                           attr->attr.name, buf, MIN_MAX_RECONN_ATT,
81                           MAX_MAX_RECONN_ATT);
82                 return -EINVAL;
83         }
84         rtrs_clt_set_max_reconnect_attempts(clt, value);
85
86         return count;
87 }
88
89 static DEVICE_ATTR_RW(max_reconnect_attempts);
90
91 static ssize_t mpath_policy_show(struct device *dev,
92                                  struct device_attribute *attr,
93                                  char *page)
94 {
95         struct rtrs_clt_sess *clt;
96
97         clt = container_of(dev, struct rtrs_clt_sess, dev);
98
99         switch (clt->mp_policy) {
100         case MP_POLICY_RR:
101                 return sysfs_emit(page, "round-robin (RR: %d)\n",
102                                   clt->mp_policy);
103         case MP_POLICY_MIN_INFLIGHT:
104                 return sysfs_emit(page, "min-inflight (MI: %d)\n",
105                                   clt->mp_policy);
106         case MP_POLICY_MIN_LATENCY:
107                 return sysfs_emit(page, "min-latency (ML: %d)\n",
108                                   clt->mp_policy);
109         default:
110                 return sysfs_emit(page, "Unknown (%d)\n", clt->mp_policy);
111         }
112 }
113
114 static ssize_t mpath_policy_store(struct device *dev,
115                                   struct device_attribute *attr,
116                                   const char *buf,
117                                   size_t count)
118 {
119         struct rtrs_clt_sess *clt;
120         int value;
121         int ret;
122         size_t len = 0;
123
124         clt = container_of(dev, struct rtrs_clt_sess, dev);
125
126         ret = kstrtoint(buf, 10, &value);
127         if (!ret && (value == MP_POLICY_RR ||
128                      value == MP_POLICY_MIN_INFLIGHT ||
129                      value == MP_POLICY_MIN_LATENCY)) {
130                 clt->mp_policy = value;
131                 return count;
132         }
133
134         /* distinguish "mi" and "min-latency" with length */
135         len = strnlen(buf, NAME_MAX);
136         if (buf[len - 1] == '\n')
137                 len--;
138
139         if (!strncasecmp(buf, "round-robin", 11) ||
140             (len == 2 && !strncasecmp(buf, "rr", 2)))
141                 clt->mp_policy = MP_POLICY_RR;
142         else if (!strncasecmp(buf, "min-inflight", 12) ||
143                  (len == 2 && !strncasecmp(buf, "mi", 2)))
144                 clt->mp_policy = MP_POLICY_MIN_INFLIGHT;
145         else if (!strncasecmp(buf, "min-latency", 11) ||
146                  (len == 2 && !strncasecmp(buf, "ml", 2)))
147                 clt->mp_policy = MP_POLICY_MIN_LATENCY;
148         else
149                 return -EINVAL;
150
151         return count;
152 }
153
154 static DEVICE_ATTR_RW(mpath_policy);
155
156 static ssize_t add_path_show(struct device *dev,
157                              struct device_attribute *attr, char *page)
158 {
159         return sysfs_emit(page,
160                 "Usage: echo [<source addr>@]<destination addr> > %s\n\n*addr ::= [ ip:<ipv4|ipv6> | gid:<gid> ]\n",
161                 attr->attr.name);
162 }
163
164 static ssize_t add_path_store(struct device *dev,
165                               struct device_attribute *attr,
166                               const char *buf, size_t count)
167 {
168         struct sockaddr_storage srcaddr, dstaddr;
169         struct rtrs_addr addr = {
170                 .src = &srcaddr,
171                 .dst = &dstaddr
172         };
173         struct rtrs_clt_sess *clt;
174         const char *nl;
175         size_t len;
176         int err;
177
178         clt = container_of(dev, struct rtrs_clt_sess, dev);
179
180         nl = strchr(buf, '\n');
181         if (nl)
182                 len = nl - buf;
183         else
184                 len = count;
185         err = rtrs_addr_to_sockaddr(buf, len, clt->port, &addr);
186         if (err)
187                 return -EINVAL;
188
189         err = rtrs_clt_create_path_from_sysfs(clt, &addr);
190         if (err)
191                 return err;
192
193         return count;
194 }
195
196 static DEVICE_ATTR_RW(add_path);
197
198 static ssize_t rtrs_clt_state_show(struct kobject *kobj,
199                                     struct kobj_attribute *attr, char *page)
200 {
201         struct rtrs_clt_path *clt_path;
202
203         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
204         if (clt_path->state == RTRS_CLT_CONNECTED)
205                 return sysfs_emit(page, "connected\n");
206
207         return sysfs_emit(page, "disconnected\n");
208 }
209
210 static struct kobj_attribute rtrs_clt_state_attr =
211         __ATTR(state, 0444, rtrs_clt_state_show, NULL);
212
213 static ssize_t rtrs_clt_reconnect_show(struct kobject *kobj,
214                                        struct kobj_attribute *attr, char *buf)
215 {
216         return sysfs_emit(buf, "Usage: echo 1 > %s\n", attr->attr.name);
217 }
218
219 static ssize_t rtrs_clt_reconnect_store(struct kobject *kobj,
220                                          struct kobj_attribute *attr,
221                                          const char *buf, size_t count)
222 {
223         struct rtrs_clt_path *clt_path;
224         int ret;
225
226         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
227         if (!sysfs_streq(buf, "1")) {
228                 rtrs_err(clt_path->clt, "%s: unknown value: '%s'\n",
229                           attr->attr.name, buf);
230                 return -EINVAL;
231         }
232         ret = rtrs_clt_reconnect_from_sysfs(clt_path);
233         if (ret)
234                 return ret;
235
236         return count;
237 }
238
239 static struct kobj_attribute rtrs_clt_reconnect_attr =
240         __ATTR(reconnect, 0644, rtrs_clt_reconnect_show,
241                rtrs_clt_reconnect_store);
242
243 static ssize_t rtrs_clt_disconnect_show(struct kobject *kobj,
244                                         struct kobj_attribute *attr, char *buf)
245 {
246         return sysfs_emit(buf, "Usage: echo 1 > %s\n", attr->attr.name);
247 }
248
249 static ssize_t rtrs_clt_disconnect_store(struct kobject *kobj,
250                                           struct kobj_attribute *attr,
251                                           const char *buf, size_t count)
252 {
253         struct rtrs_clt_path *clt_path;
254
255         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
256         if (!sysfs_streq(buf, "1")) {
257                 rtrs_err(clt_path->clt, "%s: unknown value: '%s'\n",
258                           attr->attr.name, buf);
259                 return -EINVAL;
260         }
261         rtrs_clt_close_conns(clt_path, true);
262
263         return count;
264 }
265
266 static struct kobj_attribute rtrs_clt_disconnect_attr =
267         __ATTR(disconnect, 0644, rtrs_clt_disconnect_show,
268                rtrs_clt_disconnect_store);
269
270 static ssize_t rtrs_clt_remove_path_show(struct kobject *kobj,
271                                          struct kobj_attribute *attr, char *buf)
272 {
273         return sysfs_emit(buf, "Usage: echo 1 > %s\n", attr->attr.name);
274 }
275
276 static ssize_t rtrs_clt_remove_path_store(struct kobject *kobj,
277                                            struct kobj_attribute *attr,
278                                            const char *buf, size_t count)
279 {
280         struct rtrs_clt_path *clt_path;
281         int ret;
282
283         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
284         if (!sysfs_streq(buf, "1")) {
285                 rtrs_err(clt_path->clt, "%s: unknown value: '%s'\n",
286                           attr->attr.name, buf);
287                 return -EINVAL;
288         }
289         ret = rtrs_clt_remove_path_from_sysfs(clt_path, &attr->attr);
290         if (ret)
291                 return ret;
292
293         return count;
294 }
295
296 static struct kobj_attribute rtrs_clt_remove_path_attr =
297         __ATTR(remove_path, 0644, rtrs_clt_remove_path_show,
298                rtrs_clt_remove_path_store);
299
300 STAT_ATTR(struct rtrs_clt_stats, cpu_migration_from,
301           rtrs_clt_stats_migration_from_cnt_to_str,
302           rtrs_clt_reset_cpu_migr_stats);
303
304 STAT_ATTR(struct rtrs_clt_stats, cpu_migration_to,
305           rtrs_clt_stats_migration_to_cnt_to_str,
306           rtrs_clt_reset_cpu_migr_stats);
307
308 STAT_ATTR(struct rtrs_clt_stats, reconnects,
309           rtrs_clt_stats_reconnects_to_str,
310           rtrs_clt_reset_reconnects_stat);
311
312 STAT_ATTR(struct rtrs_clt_stats, rdma,
313           rtrs_clt_stats_rdma_to_str,
314           rtrs_clt_reset_rdma_stats);
315
316 STAT_ATTR(struct rtrs_clt_stats, reset_all,
317           rtrs_clt_reset_all_help,
318           rtrs_clt_reset_all_stats);
319
320 static struct attribute *rtrs_clt_stats_attrs[] = {
321         &cpu_migration_from_attr.attr,
322         &cpu_migration_to_attr.attr,
323         &reconnects_attr.attr,
324         &rdma_attr.attr,
325         &reset_all_attr.attr,
326         NULL
327 };
328
329 static const struct attribute_group rtrs_clt_stats_attr_group = {
330         .attrs = rtrs_clt_stats_attrs,
331 };
332
333 static ssize_t rtrs_clt_hca_port_show(struct kobject *kobj,
334                                        struct kobj_attribute *attr,
335                                        char *page)
336 {
337         struct rtrs_clt_path *clt_path;
338
339         clt_path = container_of(kobj, typeof(*clt_path), kobj);
340
341         return sysfs_emit(page, "%u\n", clt_path->hca_port);
342 }
343
344 static struct kobj_attribute rtrs_clt_hca_port_attr =
345         __ATTR(hca_port, 0444, rtrs_clt_hca_port_show, NULL);
346
347 static ssize_t rtrs_clt_hca_name_show(struct kobject *kobj,
348                                        struct kobj_attribute *attr,
349                                        char *page)
350 {
351         struct rtrs_clt_path *clt_path;
352
353         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
354
355         return sysfs_emit(page, "%s\n", clt_path->hca_name);
356 }
357
358 static struct kobj_attribute rtrs_clt_hca_name_attr =
359         __ATTR(hca_name, 0444, rtrs_clt_hca_name_show, NULL);
360
361 static ssize_t rtrs_clt_cur_latency_show(struct kobject *kobj,
362                                     struct kobj_attribute *attr,
363                                     char *page)
364 {
365         struct rtrs_clt_path *clt_path;
366
367         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
368
369         return sysfs_emit(page, "%lld ns\n",
370                           ktime_to_ns(clt_path->s.hb_cur_latency));
371 }
372
373 static struct kobj_attribute rtrs_clt_cur_latency_attr =
374         __ATTR(cur_latency, 0444, rtrs_clt_cur_latency_show, NULL);
375
376 static ssize_t rtrs_clt_src_addr_show(struct kobject *kobj,
377                                        struct kobj_attribute *attr,
378                                        char *page)
379 {
380         struct rtrs_clt_path *clt_path;
381         int len;
382
383         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
384         len = sockaddr_to_str((struct sockaddr *)&clt_path->s.src_addr, page,
385                               PAGE_SIZE);
386         len += sysfs_emit_at(page, len, "\n");
387         return len;
388 }
389
390 static struct kobj_attribute rtrs_clt_src_addr_attr =
391         __ATTR(src_addr, 0444, rtrs_clt_src_addr_show, NULL);
392
393 static ssize_t rtrs_clt_dst_addr_show(struct kobject *kobj,
394                                        struct kobj_attribute *attr,
395                                        char *page)
396 {
397         struct rtrs_clt_path *clt_path;
398         int len;
399
400         clt_path = container_of(kobj, struct rtrs_clt_path, kobj);
401         len = sockaddr_to_str((struct sockaddr *)&clt_path->s.dst_addr, page,
402                               PAGE_SIZE);
403         len += sysfs_emit_at(page, len, "\n");
404         return len;
405 }
406
407 static struct kobj_attribute rtrs_clt_dst_addr_attr =
408         __ATTR(dst_addr, 0444, rtrs_clt_dst_addr_show, NULL);
409
410 static struct attribute *rtrs_clt_path_attrs[] = {
411         &rtrs_clt_hca_name_attr.attr,
412         &rtrs_clt_hca_port_attr.attr,
413         &rtrs_clt_src_addr_attr.attr,
414         &rtrs_clt_dst_addr_attr.attr,
415         &rtrs_clt_state_attr.attr,
416         &rtrs_clt_reconnect_attr.attr,
417         &rtrs_clt_disconnect_attr.attr,
418         &rtrs_clt_remove_path_attr.attr,
419         &rtrs_clt_cur_latency_attr.attr,
420         NULL,
421 };
422
423 static const struct attribute_group rtrs_clt_path_attr_group = {
424         .attrs = rtrs_clt_path_attrs,
425 };
426
427 int rtrs_clt_create_path_files(struct rtrs_clt_path *clt_path)
428 {
429         struct rtrs_clt_sess *clt = clt_path->clt;
430         char str[NAME_MAX];
431         int err;
432         struct rtrs_addr path = {
433                 .src = &clt_path->s.src_addr,
434                 .dst = &clt_path->s.dst_addr,
435         };
436
437         rtrs_addr_to_str(&path, str, sizeof(str));
438         err = kobject_init_and_add(&clt_path->kobj, &ktype_sess,
439                                    clt->kobj_paths,
440                                    "%s", str);
441         if (err) {
442                 pr_err("kobject_init_and_add: %d\n", err);
443                 kobject_put(&clt_path->kobj);
444                 return err;
445         }
446         err = sysfs_create_group(&clt_path->kobj, &rtrs_clt_path_attr_group);
447         if (err) {
448                 pr_err("sysfs_create_group(): %d\n", err);
449                 goto put_kobj;
450         }
451         err = kobject_init_and_add(&clt_path->stats->kobj_stats, &ktype_stats,
452                                    &clt_path->kobj, "stats");
453         if (err) {
454                 pr_err("kobject_init_and_add: %d\n", err);
455                 kobject_put(&clt_path->stats->kobj_stats);
456                 goto remove_group;
457         }
458
459         err = sysfs_create_group(&clt_path->stats->kobj_stats,
460                                  &rtrs_clt_stats_attr_group);
461         if (err) {
462                 pr_err("failed to create stats sysfs group, err: %d\n", err);
463                 goto put_kobj_stats;
464         }
465
466         return 0;
467
468 put_kobj_stats:
469         kobject_del(&clt_path->stats->kobj_stats);
470         kobject_put(&clt_path->stats->kobj_stats);
471 remove_group:
472         sysfs_remove_group(&clt_path->kobj, &rtrs_clt_path_attr_group);
473 put_kobj:
474         kobject_del(&clt_path->kobj);
475         kobject_put(&clt_path->kobj);
476
477         return err;
478 }
479
480 void rtrs_clt_destroy_path_files(struct rtrs_clt_path *clt_path,
481                                   const struct attribute *sysfs_self)
482 {
483         kobject_del(&clt_path->stats->kobj_stats);
484         kobject_put(&clt_path->stats->kobj_stats);
485         if (sysfs_self)
486                 sysfs_remove_file_self(&clt_path->kobj, sysfs_self);
487         kobject_del(&clt_path->kobj);
488 }
489
490 static struct attribute *rtrs_clt_attrs[] = {
491         &dev_attr_max_reconnect_attempts.attr,
492         &dev_attr_mpath_policy.attr,
493         &dev_attr_add_path.attr,
494         NULL,
495 };
496
497 static const struct attribute_group rtrs_clt_attr_group = {
498         .attrs = rtrs_clt_attrs,
499 };
500
501 int rtrs_clt_create_sysfs_root_files(struct rtrs_clt_sess *clt)
502 {
503         return sysfs_create_group(&clt->dev.kobj, &rtrs_clt_attr_group);
504 }
505
506 void rtrs_clt_destroy_sysfs_root(struct rtrs_clt_sess *clt)
507 {
508         sysfs_remove_group(&clt->dev.kobj, &rtrs_clt_attr_group);
509
510         if (clt->kobj_paths) {
511                 kobject_del(clt->kobj_paths);
512                 kobject_put(clt->kobj_paths);
513         }
514 }