1 /*
2 * Copyright (c) 2015-2016, Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2015, Intel Corp., Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 */
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39
40 #include <rdma/fi_errno.h>
41
42 #include "ofi.h"
43 #include "ofi_list.h"
44
45
46 extern int ofi_init;
47 extern void fi_ini(void);
48
49 struct fi_param_entry {
50 const struct fi_provider *provider;
51 char *name;
52 enum fi_param_type type;
53 char *help_string;
54 char *env_var_name;
55 struct dlist_entry entry;
56 };
57
58 /* TODO: Add locking around param_list when adding dynamic removal */
59 static DEFINE_LIST(param_list);
60
61
62 static struct fi_param_entry *
fi_find_param(const struct fi_provider * provider,const char * param_name)63 fi_find_param(const struct fi_provider *provider, const char *param_name)
64 {
65 struct fi_param_entry *param;
66 struct dlist_entry *entry;
67
68 for (entry = param_list.next; entry != ¶m_list; entry = entry->next) {
69 param = container_of(entry, struct fi_param_entry, entry);
70 if (param->provider == provider &&
71 strcmp(param->name, param_name) == 0) {
72 return param;
73 }
74 }
75
76 FI_DBG(provider, FI_LOG_CORE,
77 "Failed to find parameter %s: was not defined\n", param_name);
78 return NULL;
79 }
80
81 __attribute__((visibility ("default"),EXTERNALLY_VISIBLE))
DEFAULT_SYMVER_PRE(fi_getparams)82 int DEFAULT_SYMVER_PRE(fi_getparams)(struct fi_param **params, int *count)
83 {
84 struct fi_param *vhead = NULL;
85 struct fi_param_entry *param;
86 struct dlist_entry *entry;
87 int cnt, i;
88 char *tmp;
89
90 if (!ofi_init)
91 fi_ini();
92
93 for (entry = param_list.next, cnt = 0; entry != ¶m_list;
94 entry = entry->next)
95 cnt++;
96
97 if (cnt == 0)
98 goto out;
99
100 // last extra entry will be all NULL
101 vhead = calloc(cnt + 1, sizeof (*vhead));
102 if (!vhead)
103 return -FI_ENOMEM;
104
105 for (entry = param_list.next, i = 0; entry != ¶m_list;
106 entry = entry->next, i++) {
107 param = container_of(entry, struct fi_param_entry, entry);
108 vhead[i].name = strdup(param->env_var_name);
109 vhead[i].type = param->type;
110 vhead[i].help_string = strdup(param->help_string);
111
112 tmp = getenv(param->env_var_name);
113 if (tmp)
114 vhead[i].value = strdup(tmp);
115
116 if (!vhead[i].name || !vhead[i].help_string) {
117 fi_freeparams(vhead);
118 return -FI_ENOMEM;
119 }
120 }
121
122 out:
123 *count = cnt;
124 *params = vhead;
125 return FI_SUCCESS;
126 }
127 DEFAULT_SYMVER(fi_getparams_, fi_getparams, FABRIC_1.0);
128
129 __attribute__((visibility ("default"),EXTERNALLY_VISIBLE))
DEFAULT_SYMVER_PRE(fi_freeparams)130 void DEFAULT_SYMVER_PRE(fi_freeparams)(struct fi_param *params)
131 {
132 int i;
133 for (i = 0; params[i].name; ++i) {
134 free((void*) params[i].name);
135 free((void*) params[i].help_string);
136 free((void*) params[i].value);
137 }
138 free(params);
139 }
140 DEFAULT_SYMVER(fi_freeparams_, fi_freeparams, FABRIC_1.0);
141
fi_free_param(struct fi_param_entry * param)142 static void fi_free_param(struct fi_param_entry *param)
143 {
144 free(param->name);
145 free(param->help_string);
146 free(param->env_var_name);
147 free(param);
148 }
149
fi_param_undefine(const struct fi_provider * provider)150 void fi_param_undefine(const struct fi_provider *provider)
151 {
152 struct fi_param_entry *param;
153 struct dlist_entry *entry;
154 struct dlist_entry *next;
155
156 for (entry = param_list.next; entry != ¶m_list; entry = next) {
157 next = entry->next;
158 param = container_of(entry, struct fi_param_entry, entry);
159 if (param->provider == provider) {
160 FI_DBG(provider, FI_LOG_CORE, "Removing param: %s\n", param->name);
161 dlist_remove(entry);
162 fi_free_param(param);
163 }
164 }
165 }
166
167 __attribute__((visibility ("default"),EXTERNALLY_VISIBLE))
DEFAULT_SYMVER_PRE(fi_param_define)168 int DEFAULT_SYMVER_PRE(fi_param_define)(const struct fi_provider *provider,
169 const char *param_name, enum fi_param_type type,
170 const char *help_string_fmt, ...)
171 {
172 int i, ret;
173 struct fi_param_entry *v;
174 char *tmp_str;
175 va_list vargs;
176
177 if (!provider)
178 provider = &core_prov;
179
180 // Check for bozo cases
181 if (param_name == NULL || help_string_fmt == NULL || *help_string_fmt == '\0') {
182 FI_DBG(provider, FI_LOG_CORE,
183 "Failed to register %s variable: provider coding error\n",
184 param_name);
185 return -FI_EINVAL;
186 }
187
188 v = calloc(1, sizeof(*v));
189 if (!v) {
190 FI_DBG(provider, FI_LOG_CORE,
191 "Failed to register %s variable: ENOMEM\n", param_name);
192 return -FI_ENOMEM;
193 }
194
195 v->provider = provider;
196 v->name = strdup(param_name);
197 v->type = type;
198
199 va_start(vargs, help_string_fmt);
200 ret = vasprintf(&v->help_string, help_string_fmt, vargs);
201 va_end(vargs);
202 if (ret < 0)
203 v->help_string = NULL;
204
205 if (provider != &core_prov) {
206 ret = asprintf(&tmp_str, "%s: %s", provider->name, v->help_string);
207 free(v->help_string);
208 if (ret < 0)
209 v->help_string = NULL;
210 v->help_string = tmp_str;
211 ret = asprintf(&v->env_var_name, "FI_%s_%s", provider->name, param_name);
212 if (ret < 0)
213 v->env_var_name = NULL;
214 } else {
215 ret = asprintf(&v->env_var_name, "FI_%s", param_name);
216 if (ret < 0)
217 v->env_var_name = NULL;
218 }
219 if (!v->name || !v->help_string || !v->env_var_name) {
220 fi_free_param(v);
221 FI_DBG(provider, FI_LOG_CORE,
222 "Failed to register %s variable: ENOMEM\n", param_name);
223 return -FI_ENOMEM;
224 }
225
226 for (i = 0; v->env_var_name[i]; ++i)
227 v->env_var_name[i] = (char) toupper(v->env_var_name[i]);
228
229 dlist_insert_tail(&v->entry, ¶m_list);
230
231 FI_DBG(provider, FI_LOG_CORE, "registered var %s\n", param_name);
232 return FI_SUCCESS;
233 }
234 DEFAULT_SYMVER(fi_param_define_, fi_param_define, FABRIC_1.0);
235
fi_parse_bool(const char * str_value)236 static int fi_parse_bool(const char *str_value)
237 {
238 if (strcmp(str_value, "0") == 0 ||
239 strcasecmp(str_value, "false") == 0 ||
240 strcasecmp(str_value, "no") == 0 ||
241 strcasecmp(str_value, "off") == 0) {
242 return 0;
243 }
244
245 if (strcmp(str_value, "1") == 0 ||
246 strcasecmp(str_value, "true") == 0 ||
247 strcasecmp(str_value, "yes") == 0 ||
248 strcasecmp(str_value, "on") == 0) {
249 return 1;
250 }
251
252 return -1;
253 }
254
255 __attribute__((visibility ("default"),EXTERNALLY_VISIBLE))
DEFAULT_SYMVER_PRE(fi_param_get)256 int DEFAULT_SYMVER_PRE(fi_param_get)(struct fi_provider *provider,
257 const char *param_name, void *value)
258 {
259 struct fi_param_entry *param;
260 char *str_value;
261 int ret = FI_SUCCESS;
262
263 if (!provider)
264 provider = &core_prov;
265
266 if (!param_name || !value) {
267 FI_DBG(provider, FI_LOG_CORE,
268 "Failed to read %s variable: provider coding error\n",
269 param_name);
270 return -FI_EINVAL;
271 }
272
273 param = fi_find_param(provider, param_name);
274 if (!param)
275 return -FI_ENOENT;
276
277 str_value = getenv(param->env_var_name);
278 if (!str_value) {
279 FI_INFO(provider, FI_LOG_CORE,
280 "variable %s=<not set>\n", param_name);
281 ret = -FI_ENODATA;
282 goto out;
283 }
284
285 switch (param->type) {
286 case FI_PARAM_STRING:
287 * ((char **) value) = str_value;
288 FI_INFO(provider, FI_LOG_CORE,
289 "read string var %s=%s\n", param_name, *(char **) value);
290 break;
291 case FI_PARAM_INT:
292 * ((int *) value) = strtol(str_value, NULL, 0);
293 FI_INFO(provider, FI_LOG_CORE,
294 "read int var %s=%d\n", param_name, *(int *) value);
295 break;
296 case FI_PARAM_BOOL:
297 * ((int *) value) = fi_parse_bool(str_value);
298 FI_INFO(provider, FI_LOG_CORE,
299 "read bool var %s=%d\n", param_name, *(int *) value);
300 if (*(int *) value == -1)
301 ret = -FI_EINVAL;
302 break;
303 case FI_PARAM_SIZE_T:
304 * ((size_t *) value) = strtol(str_value, NULL, 0);
305 FI_INFO(provider, FI_LOG_CORE,
306 "read long var %s=%zu\n", param_name, *(size_t *) value);
307 break;
308 }
309
310 out:
311 return ret;
312 }
313 DEFAULT_SYMVER(fi_param_get_, fi_param_get, FABRIC_1.0);
314
315
fi_param_init(void)316 void fi_param_init(void)
317 {
318 dlist_init(¶m_list);
319 }
320
fi_param_fini(void)321 void fi_param_fini(void)
322 {
323 struct fi_param_entry *param;
324 struct dlist_entry *entry;
325
326 while (!dlist_empty(¶m_list)) {
327 entry = param_list.next;
328 param = container_of(entry, struct fi_param_entry, entry);
329 dlist_remove(entry);
330 fi_free_param(param);
331 }
332 }
333