1 /*
2 * Copyright (c) 2014-2016 Intel Corporation, Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/time.h>
36
37 #include <ofi_util.h>
38 #include <ofi.h>
39
40 static DEFINE_LIST(fabric_list);
41 extern struct ofi_common_locks common_locks;
42
ofi_fabric_insert(struct util_fabric * fabric)43 void ofi_fabric_insert(struct util_fabric *fabric)
44 {
45 pthread_mutex_lock(&common_locks.util_fabric_lock);
46 dlist_insert_tail(&fabric->list_entry, &fabric_list);
47 pthread_mutex_unlock(&common_locks.util_fabric_lock);
48 }
49
util_match_fabric(struct dlist_entry * item,const void * arg)50 static int util_match_fabric(struct dlist_entry *item, const void *arg)
51 {
52 struct util_fabric *fabric;
53 struct util_fabric_info *fabric_info = (struct util_fabric_info *)arg;
54
55 fabric = container_of(item, struct util_fabric, list_entry);
56 return (fabric_info->prov == fabric->prov) &&
57 !strcmp(fabric->name, fabric_info->name);
58 }
59
ofi_fabric_remove(struct util_fabric * fabric)60 void ofi_fabric_remove(struct util_fabric *fabric)
61 {
62 pthread_mutex_lock(&common_locks.util_fabric_lock);
63 dlist_remove(&fabric->list_entry);
64 pthread_mutex_unlock(&common_locks.util_fabric_lock);
65 }
66
67
ofi_fid_match(struct dlist_entry * entry,const void * fid)68 static int ofi_fid_match(struct dlist_entry *entry, const void *fid)
69 {
70 struct fid_list_entry *item;
71 item = container_of(entry, struct fid_list_entry, entry);
72 return (item->fid == fid);
73 }
74
fid_list_insert(struct dlist_entry * fid_list,fastlock_t * lock,struct fid * fid)75 int fid_list_insert(struct dlist_entry *fid_list, fastlock_t *lock,
76 struct fid *fid)
77 {
78 int ret = 0;
79 struct dlist_entry *entry;
80 struct fid_list_entry *item;
81
82 fastlock_acquire(lock);
83 entry = dlist_find_first_match(fid_list, ofi_fid_match, fid);
84 if (entry)
85 goto out;
86
87 item = calloc(1, sizeof(*item));
88 if (!item) {
89 ret = -FI_ENOMEM;
90 goto out;
91 }
92
93 item->fid = fid;
94 dlist_insert_tail(&item->entry, fid_list);
95 out:
96 fastlock_release(lock);
97 return ret;
98 }
99
fid_list_remove(struct dlist_entry * fid_list,fastlock_t * lock,struct fid * fid)100 void fid_list_remove(struct dlist_entry *fid_list, fastlock_t *lock,
101 struct fid *fid)
102 {
103 struct fid_list_entry *item;
104 struct dlist_entry *entry;
105
106 fastlock_acquire(lock);
107 entry = dlist_remove_first_match(fid_list, ofi_fid_match, fid);
108 fastlock_release(lock);
109
110 if (entry) {
111 item = container_of(entry, struct fid_list_entry, entry);
112 free(item);
113 }
114 }
115
util_find_domain(struct dlist_entry * item,const void * arg)116 static int util_find_domain(struct dlist_entry *item, const void *arg)
117 {
118 const struct util_domain *domain;
119 const struct fi_info *info = arg;
120
121 domain = container_of(item, struct util_domain, list_entry);
122
123 return !strcmp(domain->name, info->domain_attr->name) &&
124 !((info->caps | info->domain_attr->caps) & ~domain->info_domain_caps) &&
125 (((info->mode | info->domain_attr->mode) &
126 domain->info_domain_mode) == domain->info_domain_mode) &&
127 ((info->domain_attr->mr_mode & domain->mr_mode) == domain->mr_mode);
128 }
129
130 /*
131 * Produces 1 fi_info output for each fi_info entry in the provider's base
132 * list (stored with util_prov), subject to the base fi_info meeting the
133 * user's hints.
134 */
util_getinfo(const struct util_prov * util_prov,uint32_t version,const char * node,const char * service,uint64_t flags,const struct fi_info * hints,struct fi_info ** info)135 int util_getinfo(const struct util_prov *util_prov, uint32_t version,
136 const char *node, const char *service, uint64_t flags,
137 const struct fi_info *hints, struct fi_info **info)
138 {
139 struct util_fabric *fabric;
140 struct util_domain *domain;
141 struct dlist_entry *item;
142 const struct fi_provider *prov = util_prov->prov;
143 struct util_fabric_info fabric_info;
144 struct fi_info *saved_info;
145 int ret, copy_dest;
146
147 FI_DBG(prov, FI_LOG_CORE, "checking info\n");
148
149 if ((flags & FI_SOURCE) && !node && !service) {
150 FI_INFO(prov, FI_LOG_CORE,
151 "FI_SOURCE set, but no node or service\n");
152 return -FI_EINVAL;
153 }
154
155 ret = ofi_prov_check_dup_info(util_prov, version, hints, info);
156 if (ret)
157 return ret;
158
159 ofi_alter_info(*info, hints, version);
160
161 saved_info = *info;
162
163 for (; *info; *info = (*info)->next) {
164
165 fabric_info.name = (*info)->fabric_attr->name;
166 fabric_info.prov = util_prov->prov;
167
168 pthread_mutex_lock(&common_locks.util_fabric_lock);
169 item = dlist_find_first_match(&fabric_list, util_match_fabric,
170 &fabric_info);
171 if (item) {
172 fabric = container_of(item, struct util_fabric, list_entry);
173 FI_DBG(prov, FI_LOG_CORE, "Found opened fabric\n");
174 (*info)->fabric_attr->fabric = &fabric->fabric_fid;
175
176 fastlock_acquire(&fabric->lock);
177 item = dlist_find_first_match(&fabric->domain_list,
178 util_find_domain, *info);
179 if (item) {
180 FI_DBG(prov, FI_LOG_CORE,
181 "Found open domain\n");
182 domain = container_of(item, struct util_domain,
183 list_entry);
184 (*info)->domain_attr->domain =
185 &domain->domain_fid;
186 }
187 fastlock_release(&fabric->lock);
188
189 }
190 pthread_mutex_unlock(&common_locks.util_fabric_lock);
191
192 if (flags & FI_SOURCE) {
193 ret = ofi_get_addr(&(*info)->addr_format, flags,
194 node, service, &(*info)->src_addr,
195 &(*info)->src_addrlen);
196 if (ret) {
197 FI_INFO(prov, FI_LOG_CORE,
198 "source address not available\n");
199 goto err;
200 }
201 copy_dest = (hints && hints->dest_addr);
202 } else {
203 if (node || service) {
204 copy_dest = 0;
205 ret = ofi_get_addr(&(*info)->addr_format,
206 flags, node, service,
207 &(*info)->dest_addr,
208 &(*info)->dest_addrlen);
209 if (ret) {
210 FI_INFO(prov, FI_LOG_CORE,
211 "cannot resolve dest address\n");
212 goto err;
213 }
214 } else {
215 copy_dest = (hints && hints->dest_addr);
216 }
217
218 if (hints && hints->src_addr) {
219 (*info)->src_addr = mem_dup(hints->src_addr,
220 hints->src_addrlen);
221 if (!(*info)->src_addr) {
222 ret = -FI_ENOMEM;
223 goto err;
224 }
225 (*info)->src_addrlen = hints->src_addrlen;
226 (*info)->addr_format = hints->addr_format;
227 }
228 }
229
230 if (copy_dest) {
231 (*info)->dest_addr = mem_dup(hints->dest_addr,
232 hints->dest_addrlen);
233 if (!(*info)->dest_addr) {
234 ret = -FI_ENOMEM;
235 goto err;
236 }
237 (*info)->dest_addrlen = hints->dest_addrlen;
238 (*info)->addr_format = hints->addr_format;
239 }
240
241 if ((*info)->dest_addr && !(*info)->src_addr) {
242 ret = ofi_get_src_addr((*info)->addr_format,
243 (*info)->dest_addr,
244 (*info)->dest_addrlen,
245 &(*info)->src_addr,
246 &(*info)->src_addrlen);
247 if (ret) {
248 FI_INFO(prov, FI_LOG_CORE,
249 "cannot resolve source address\n");
250 }
251 }
252 }
253
254 *info = saved_info;
255
256 return 0;
257
258 err:
259 fi_freeinfo(*info);
260 return ret;
261 }
262
util_set_netif_names(struct fi_info * info,struct ofi_addr_list_entry * addr_entry)263 static void util_set_netif_names(struct fi_info *info,
264 struct ofi_addr_list_entry *addr_entry)
265 {
266 char *name;
267
268 name = strdup(addr_entry->net_name);
269 if (name) {
270 free(info->fabric_attr->name);
271 info->fabric_attr->name = name;
272 }
273
274 name = strdup(addr_entry->ifa_name);
275 if (name) {
276 free(info->domain_attr->name);
277 info->domain_attr->name = name;
278 }
279 }
280
281 /*
282 * Produces 1 fi_info output for each usable IP address in the system for the
283 * given fi_info input.
284 */
285 #if HAVE_GETIFADDRS
util_getinfo_ifs(const struct util_prov * prov,struct fi_info * src_info,struct fi_info ** head,struct fi_info ** tail)286 static void util_getinfo_ifs(const struct util_prov *prov, struct fi_info *src_info,
287 struct fi_info **head, struct fi_info **tail)
288 {
289 struct fi_info *cur;
290 struct slist addr_list;
291 size_t addrlen;
292 uint32_t addr_format;
293 struct slist_entry *entry, *prev;
294 struct ofi_addr_list_entry *addr_entry;
295
296 *head = *tail = NULL;
297 slist_init(&addr_list);
298
299 ofi_get_list_of_addr(prov->prov, "iface", &addr_list);
300
301 (void) prev; /* Makes compiler happy */
302 slist_foreach(&addr_list, entry, prev) {
303 addr_entry = container_of(entry, struct ofi_addr_list_entry, entry);
304
305 cur = fi_dupinfo(src_info);
306 if (!cur)
307 break;
308
309 if (!*head) {
310 *head = cur;
311 FI_INFO(prov->prov, FI_LOG_CORE, "Chosen addr for using: %s,"
312 " speed %zu\n", addr_entry->ipstr, addr_entry->speed);
313 } else {
314 (*tail)->next = cur;
315 }
316 *tail = cur;
317
318 switch (addr_entry->ipaddr.sin.sin_family) {
319 case AF_INET:
320 addrlen = sizeof(struct sockaddr_in);
321 addr_format = FI_SOCKADDR_IN;
322 break;
323 case AF_INET6:
324 addrlen = sizeof(struct sockaddr_in6);
325 addr_format = FI_SOCKADDR_IN6;
326 break;
327 default:
328 continue;
329 }
330
331 cur->src_addr = mem_dup(&addr_entry->ipaddr, addrlen);
332 if (cur->src_addr) {
333 cur->src_addrlen = addrlen;
334 cur->addr_format = addr_format;
335 }
336 util_set_netif_names(cur, addr_entry);
337 }
338
339 ofi_free_list_of_addr(&addr_list);
340 if (!*head) {
341 *head = src_info;
342 *tail = src_info;
343 }
344 }
345 #else
util_getinfo_ifs(const struct util_prov * prov,struct fi_info * src_info,struct fi_info ** head,struct fi_info ** tail)346 static void util_getinfo_ifs(const struct util_prov *prov, struct fi_info *src_info,
347 struct fi_info **head, struct fi_info **tail)
348 {
349 *head = src_info;
350 *tail = src_info;
351 }
352 #endif
353
util_match_addr(struct slist_entry * entry,const void * addr)354 static int util_match_addr(struct slist_entry *entry, const void *addr)
355 {
356 struct ofi_addr_list_entry *addr_entry;
357
358 addr_entry = container_of(entry, struct ofi_addr_list_entry, entry);
359 return ofi_equals_ipaddr(&addr_entry->ipaddr.sa, addr);
360 }
361
ofi_ip_getinfo(const struct util_prov * prov,uint32_t version,const char * node,const char * service,uint64_t flags,const struct fi_info * hints,struct fi_info ** info)362 int ofi_ip_getinfo(const struct util_prov *prov, uint32_t version,
363 const char *node, const char *service, uint64_t flags,
364 const struct fi_info *hints, struct fi_info **info)
365 {
366 struct fi_info *head, *tail, *cur, **prev;
367 struct ofi_addr_list_entry *addr_entry;
368 struct slist addr_list;
369 struct slist_entry *entry;
370 int ret;
371
372 ret = util_getinfo(prov, version, node, service, flags,
373 hints, info);
374 if (ret)
375 return ret;
376
377 prev = info;
378 for (cur = *info; cur; cur = cur->next) {
379 if (!cur->src_addr && !cur->dest_addr) {
380 util_getinfo_ifs(prov, cur, &head, &tail);
381 if (head != cur) {
382 tail->next = (*prev)->next;
383 *prev = head;
384
385 cur->next = NULL;
386 fi_freeinfo(cur);
387 cur = tail;
388 }
389 } else if (cur->src_addr) {
390 slist_init(&addr_list);
391 ofi_get_list_of_addr(prov->prov, "iface", &addr_list);
392
393 entry = slist_find_first_match(&addr_list, util_match_addr,
394 (*info)->src_addr);
395 if (entry) {
396 addr_entry = container_of(entry,
397 struct ofi_addr_list_entry, entry);
398 util_set_netif_names(cur, addr_entry);
399 }
400 ofi_free_list_of_addr(&addr_list);
401 }
402 prev = &cur->next;
403 }
404
405 return 0;
406 }
407