brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · 4aa80c9 Raw
515 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * RDMA Transport Layer4 *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_fmt10#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt11 12#include "rtrs-pri.h"13#include "rtrs-clt.h"14#include "rtrs-log.h"15 16#define MIN_MAX_RECONN_ATT -117#define MAX_MAX_RECONN_ATT 999918 19static 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 28static struct kobj_type ktype_sess = {29	.sysfs_ops = &kobj_sysfs_ops,30	.release = rtrs_clt_path_release31};32 33static 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 44static struct kobj_type ktype_stats = {45	.sysfs_ops = &kobj_sysfs_ops,46	.release = rtrs_clt_path_stats_release,47};48 49static 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 60static 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 89static DEVICE_ATTR_RW(max_reconnect_attempts);90 91static 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 114static 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 (len && 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	else149		return -EINVAL;150 151	return count;152}153 154static DEVICE_ATTR_RW(mpath_policy);155 156static 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 164static 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 = &dstaddr172	};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	else184		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 196static DEVICE_ATTR_RW(add_path);197 198static 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 210static struct kobj_attribute rtrs_clt_state_attr =211	__ATTR(state, 0444, rtrs_clt_state_show, NULL);212 213static 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 219static 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 239static struct kobj_attribute rtrs_clt_reconnect_attr =240	__ATTR(reconnect, 0644, rtrs_clt_reconnect_show,241	       rtrs_clt_reconnect_store);242 243static 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 249static 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 266static struct kobj_attribute rtrs_clt_disconnect_attr =267	__ATTR(disconnect, 0644, rtrs_clt_disconnect_show,268	       rtrs_clt_disconnect_store);269 270static 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 276static 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 296static 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 300STAT_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 304STAT_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 308STAT_ATTR(struct rtrs_clt_stats, reconnects,309	  rtrs_clt_stats_reconnects_to_str,310	  rtrs_clt_reset_reconnects_stat);311 312STAT_ATTR(struct rtrs_clt_stats, rdma,313	  rtrs_clt_stats_rdma_to_str,314	  rtrs_clt_reset_rdma_stats);315 316STAT_ATTR(struct rtrs_clt_stats, reset_all,317	  rtrs_clt_reset_all_help,318	  rtrs_clt_reset_all_stats);319 320static 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	NULL327};328 329static const struct attribute_group rtrs_clt_stats_attr_group = {330	.attrs = rtrs_clt_stats_attrs,331};332 333static 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 344static struct kobj_attribute rtrs_clt_hca_port_attr =345	__ATTR(hca_port, 0444, rtrs_clt_hca_port_show, NULL);346 347static 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 358static struct kobj_attribute rtrs_clt_hca_name_attr =359	__ATTR(hca_name, 0444, rtrs_clt_hca_name_show, NULL);360 361static 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 373static struct kobj_attribute rtrs_clt_cur_latency_attr =374	__ATTR(cur_latency, 0444, rtrs_clt_cur_latency_show, NULL);375 376static 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 390static struct kobj_attribute rtrs_clt_src_addr_attr =391	__ATTR(src_addr, 0444, rtrs_clt_src_addr_show, NULL);392 393static 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 407static struct kobj_attribute rtrs_clt_dst_addr_attr =408	__ATTR(dst_addr, 0444, rtrs_clt_dst_addr_show, NULL);409 410static 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 423static const struct attribute_group rtrs_clt_path_attr_group = {424	.attrs = rtrs_clt_path_attrs,425};426 427int 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 468put_kobj_stats:469	kobject_del(&clt_path->stats->kobj_stats);470	kobject_put(&clt_path->stats->kobj_stats);471remove_group:472	sysfs_remove_group(&clt_path->kobj, &rtrs_clt_path_attr_group);473put_kobj:474	kobject_del(&clt_path->kobj);475	kobject_put(&clt_path->kobj);476 477	return err;478}479 480void 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 490static 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 497static const struct attribute_group rtrs_clt_attr_group = {498	.attrs = rtrs_clt_attrs,499};500 501int 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 506void 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}515