1 /*
2  * Copyright (c) 2015-2016 Intel Corporation. All rights reserved.
3  * Copyright (c) 2018, Cisco Systems, 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 #include <stdio.h>
35 
36 #include <shared/ofi_str.h>
37 #include <ofi_util.h>
38 
39 #define OFI_MSG_DIRECTION_CAPS	(FI_SEND | FI_RECV)
40 #define OFI_RMA_DIRECTION_CAPS	(FI_READ | FI_WRITE | \
41 				 FI_REMOTE_READ | FI_REMOTE_WRITE)
42 
fi_valid_addr_format(uint32_t prov_format,uint32_t user_format)43 static int fi_valid_addr_format(uint32_t prov_format, uint32_t user_format)
44 {
45 	if (user_format == FI_FORMAT_UNSPEC || prov_format == FI_FORMAT_UNSPEC)
46 		return 1;
47 
48 	switch (prov_format) {
49 	case FI_SOCKADDR:
50 		/* Provider supports INET and INET6 */
51 		return user_format <= FI_SOCKADDR_IN6;
52 	case FI_SOCKADDR_IN:
53 		/* Provider supports INET only */
54 		return user_format <= FI_SOCKADDR_IN;
55 	case FI_SOCKADDR_IN6:
56 		/* Provider supports INET6 only */
57 		return user_format <= FI_SOCKADDR_IN6;
58 	case FI_SOCKADDR_IB:
59 		/* Provider must support IB, INET, and INET6 */
60 		return user_format <= FI_SOCKADDR_IB;
61 	default:
62 		return prov_format == user_format;
63 	}
64 }
65 
66 /*
67 char *ofi_strdup_head(const char *str)
68 {
69 	char *delim;
70 	delim = strchr(str, OFI_NAME_DELIM);
71 	return delim ? strndup(str, delim - str) : strdup(str);
72 }
73 
74 char *ofi_strdup_tail(const char *str)
75 {
76 	char *delim;
77 	delim = strchr(str, OFI_NAME_DELIM);
78 	return delim ? strup(delim + 1) : strdup(str);
79 }
80 */
81 
ofi_strdup_append(const char * head,const char * tail)82 char *ofi_strdup_append(const char *head, const char *tail)
83 {
84 	char *str;
85 	size_t len;
86 
87 	len = strlen(head) + strlen(tail) + 2;
88 	str = malloc(len);
89 	if (str)
90 		sprintf(str, "%s%c%s", head, OFI_NAME_DELIM, tail);
91 	return str;
92 }
93 
ofi_exclude_prov_name(char ** prov_name_list,const char * util_prov_name)94 int ofi_exclude_prov_name(char **prov_name_list, const char *util_prov_name)
95 {
96 	char *exclude, *name, *temp;
97 
98 	exclude = malloc(strlen(util_prov_name) + 2);
99 	if (!exclude)
100 		return -FI_ENOMEM;
101 
102 	exclude[0] = '^';
103 	strcpy(&exclude[1], util_prov_name);
104 
105 	if (!*prov_name_list)
106 		goto out;
107 
108 	name = strdup(*prov_name_list);
109 	if (!name)
110 		goto err1;
111 
112 	ofi_rm_substr_delim(name, util_prov_name, OFI_NAME_DELIM);
113 
114 	if (strlen(name)) {
115 		temp = ofi_strdup_append(name, exclude);
116 		if (!temp)
117 			goto err2;
118 		free(exclude);
119 		exclude = temp;
120 	}
121 	free(name);
122 	free(*prov_name_list);
123 out:
124 	*prov_name_list = exclude;
125 	return 0;
126 err2:
127 	free(name);
128 err1:
129 	free(exclude);
130 	return -FI_ENOMEM;
131 }
132 
ofi_dup_addr(const struct fi_info * info,struct fi_info * dup)133 static int ofi_dup_addr(const struct fi_info *info, struct fi_info *dup)
134 {
135 	dup->addr_format = info->addr_format;
136 	if (info->src_addr) {
137 		dup->src_addrlen = info->src_addrlen;
138 		dup->src_addr = mem_dup(info->src_addr, info->src_addrlen);
139 		if (dup->src_addr == NULL)
140 			return -FI_ENOMEM;
141 	}
142 	if (info->dest_addr) {
143 		dup->dest_addrlen = info->dest_addrlen;
144 		dup->dest_addr = mem_dup(info->dest_addr, info->dest_addrlen);
145 		if (dup->dest_addr == NULL) {
146 			free(dup->src_addr);
147 			dup->src_addr = NULL;
148 			return -FI_ENOMEM;
149 		}
150 	}
151 	return 0;
152 }
153 
ofi_info_to_core(uint32_t version,const struct fi_provider * prov,const struct fi_info * util_info,ofi_alter_info_t info_to_core,struct fi_info ** core_hints)154 static int ofi_info_to_core(uint32_t version, const struct fi_provider *prov,
155 			    const struct fi_info *util_info,
156 			    ofi_alter_info_t info_to_core,
157 			    struct fi_info **core_hints)
158 {
159 	int ret = -FI_ENOMEM;
160 
161 	if (!(*core_hints = fi_allocinfo()))
162 		return -FI_ENOMEM;
163 
164 	if (info_to_core(version, util_info, *core_hints))
165 		goto err;
166 
167 	if (!util_info)
168 		return 0;
169 
170 	if (ofi_dup_addr(util_info, *core_hints))
171 		goto err;
172 
173 	if (util_info->fabric_attr) {
174 		if (util_info->fabric_attr->name) {
175 			(*core_hints)->fabric_attr->name =
176 				strdup(util_info->fabric_attr->name);
177 			if (!(*core_hints)->fabric_attr->name) {
178 				FI_WARN(prov, FI_LOG_FABRIC,
179 					"Unable to allocate fabric name\n");
180 				goto err;
181 			}
182 		}
183 
184 		if (util_info->fabric_attr->prov_name) {
185 			(*core_hints)->fabric_attr->prov_name =
186 				strdup(util_info->fabric_attr->prov_name);
187 			if (!(*core_hints)->fabric_attr->prov_name) {
188 				FI_WARN(prov, FI_LOG_FABRIC,
189 					"Unable to alloc prov name\n");
190 				goto err;
191 			}
192 			ret = ofi_exclude_prov_name(
193 					&(*core_hints)->fabric_attr->prov_name,
194 					prov->name);
195 			if (ret)
196 				goto err;
197 		}
198 	}
199 
200 	if (util_info->domain_attr && util_info->domain_attr->name) {
201 		(*core_hints)->domain_attr->name =
202 			strdup(util_info->domain_attr->name);
203 		if (!(*core_hints)->domain_attr->name) {
204 			FI_WARN(prov, FI_LOG_FABRIC,
205 				"Unable to allocate domain name\n");
206 			goto err;
207 		}
208 	}
209 	return 0;
210 
211 err:
212 	fi_freeinfo(*core_hints);
213 	return ret;
214 }
215 
ofi_info_to_util(uint32_t version,const struct fi_provider * prov,struct fi_info * core_info,ofi_alter_info_t info_to_util,struct fi_info ** util_info)216 static int ofi_info_to_util(uint32_t version, const struct fi_provider *prov,
217 			    struct fi_info *core_info,
218 			    ofi_alter_info_t info_to_util,
219 			    struct fi_info **util_info)
220 {
221 	if (!(*util_info = fi_allocinfo()))
222 		return -FI_ENOMEM;
223 
224 	if (info_to_util(version, core_info, *util_info))
225 		goto err;
226 
227 	if (ofi_dup_addr(core_info, *util_info))
228 		goto err;
229 
230 	/* Release 1.4 brought standardized domain names across IP based
231 	 * providers. Before this release, the usNIC provider would return a
232 	 * NULL domain name from fi_getinfo. For compatibility reasons, allow a
233 	 * NULL domain name when apps are requesting version < 1.4.
234 	 */
235 	assert(FI_VERSION_LT(1, 4) || core_info->domain_attr->name);
236 
237 	if (core_info->domain_attr->name) {
238 		(*util_info)->domain_attr->name =
239 			strdup(core_info->domain_attr->name);
240 
241 		if (!(*util_info)->domain_attr->name) {
242 			FI_WARN(prov, FI_LOG_FABRIC,
243 				"Unable to allocate domain name\n");
244 			goto err;
245 		}
246 	}
247 
248 	(*util_info)->fabric_attr->name = strdup(core_info->fabric_attr->name);
249 	if (!(*util_info)->fabric_attr->name) {
250 		FI_WARN(prov, FI_LOG_FABRIC,
251 			"Unable to allocate fabric name\n");
252 		goto err;
253 	}
254 
255 	(*util_info)->fabric_attr->prov_name = strdup(core_info->fabric_attr->
256 						      prov_name);
257 	if (!(*util_info)->fabric_attr->prov_name) {
258 		FI_WARN(prov, FI_LOG_FABRIC,
259 			"Unable to allocate fabric name\n");
260 		goto err;
261 	}
262 
263 	return 0;
264 err:
265 	fi_freeinfo(*util_info);
266 	return -FI_ENOMEM;
267 }
268 
ofi_get_core_info(uint32_t version,const char * node,const char * service,uint64_t flags,const struct util_prov * util_prov,const struct fi_info * util_hints,ofi_alter_info_t info_to_core,struct fi_info ** core_info)269 int ofi_get_core_info(uint32_t version, const char *node, const char *service,
270 		      uint64_t flags, const struct util_prov *util_prov,
271 		      const struct fi_info *util_hints, ofi_alter_info_t info_to_core,
272 		      struct fi_info **core_info)
273 {
274 	struct fi_info *core_hints = NULL;
275 	int ret;
276 
277 	ret = ofi_prov_check_info(util_prov, version, util_hints);
278 	if (ret)
279 		return ret;
280 
281 	ret = ofi_info_to_core(version, util_prov->prov, util_hints, info_to_core,
282 			       &core_hints);
283 	if (ret)
284 		return ret;
285 
286 	FI_DBG(util_prov->prov, FI_LOG_CORE, "--- Begin ofi_get_core_info ---\n");
287 
288 	ret = fi_getinfo(version, node, service, flags | OFI_CORE_PROV_ONLY,
289 			 core_hints, core_info);
290 
291 	FI_DBG(util_prov->prov, FI_LOG_CORE, "--- End ofi_get_core_info ---\n");
292 
293 	fi_freeinfo(core_hints);
294 	return ret;
295 }
296 
ofix_getinfo(uint32_t version,const char * node,const char * service,uint64_t flags,const struct util_prov * util_prov,const struct fi_info * hints,ofi_alter_info_t info_to_core,ofi_alter_info_t info_to_util,struct fi_info ** info)297 int ofix_getinfo(uint32_t version, const char *node, const char *service,
298 		 uint64_t flags, const struct util_prov *util_prov,
299 		 const struct fi_info *hints, ofi_alter_info_t info_to_core,
300 		 ofi_alter_info_t info_to_util, struct fi_info **info)
301 {
302 	struct fi_info *core_info, *util_info, *cur, *tail;
303 	int ret;
304 
305 	ret = ofi_get_core_info(version, node, service, flags, util_prov,
306 				hints, info_to_core, &core_info);
307 	if (ret)
308 		return ret;
309 
310 	*info = tail = NULL;
311 	for (cur = core_info; cur; cur = cur->next) {
312 		ret = ofi_info_to_util(version, util_prov->prov, cur,
313 				       info_to_util, &util_info);
314 		if (ret) {
315 			fi_freeinfo(*info);
316 			break;
317 		}
318 
319 		ofi_alter_info(util_info, hints, version);
320 		if (!*info)
321 			*info = util_info;
322 		else
323 			tail->next = util_info;
324 		tail = util_info;
325 	}
326 	fi_freeinfo(core_info);
327 	return ret;
328 }
329 
330 /* Caller should use only fabric_attr in returned core_info */
ofi_get_core_info_fabric(const struct fi_provider * prov,const struct fi_fabric_attr * util_attr,struct fi_info ** core_info)331 int ofi_get_core_info_fabric(const struct fi_provider *prov,
332 			     const struct fi_fabric_attr *util_attr,
333 			     struct fi_info **core_info)
334 {
335 	struct fi_info hints;
336 	int ret;
337 
338 	/* ofix_getinfo() would append utility provider name after core / lower
339 	 * layer provider name */
340 	if (!strstr(util_attr->prov_name, prov->name))
341 		return -FI_ENODATA;
342 
343 	memset(&hints, 0, sizeof hints);
344 	if (!(hints.fabric_attr = calloc(1, sizeof(*hints.fabric_attr))))
345 		return -FI_ENOMEM;
346 
347 	hints.fabric_attr->prov_name = strdup(util_attr->prov_name);
348 	if (!hints.fabric_attr->prov_name) {
349 		ret = -FI_ENOMEM;
350 		goto out;
351 	}
352 
353 	ret = ofi_exclude_prov_name(&hints.fabric_attr->prov_name, prov->name);
354 	if (ret)
355 		goto out;
356 
357 	hints.fabric_attr->name = util_attr->name;
358 	hints.fabric_attr->api_version = util_attr->api_version;
359 	hints.mode = ~0;
360 
361 	ret = fi_getinfo(util_attr->api_version, NULL, NULL, OFI_CORE_PROV_ONLY,
362 	                 &hints, core_info);
363 
364 	free(hints.fabric_attr->prov_name);
365 out:
366 	free(hints.fabric_attr);
367 	return ret;
368 }
369 
ofi_check_fabric_attr(const struct fi_provider * prov,const struct fi_fabric_attr * prov_attr,const struct fi_fabric_attr * user_attr)370 int ofi_check_fabric_attr(const struct fi_provider *prov,
371 			  const struct fi_fabric_attr *prov_attr,
372 			  const struct fi_fabric_attr *user_attr)
373 {
374 	/* Provider names are checked by the framework */
375 
376 	if (user_attr->prov_version > prov_attr->prov_version) {
377 		FI_INFO(prov, FI_LOG_CORE, "Unsupported provider version\n");
378 		return -FI_ENODATA;
379 	}
380 
381 	if (FI_VERSION_LT(user_attr->api_version, prov_attr->api_version)) {
382 		FI_INFO(prov, FI_LOG_CORE, "Unsupported api version\n");
383 		return -FI_ENODATA;
384 	}
385 
386 	return 0;
387 }
388 
389 /*
390  * Threading models ranked by order of parallelism.
391  */
fi_thread_level(enum fi_threading thread_model)392 static int fi_thread_level(enum fi_threading thread_model)
393 {
394 	switch (thread_model) {
395 	case FI_THREAD_SAFE:
396 		return 1;
397 	case FI_THREAD_FID:
398 		return 2;
399 	case FI_THREAD_ENDPOINT:
400 		return 3;
401 	case FI_THREAD_COMPLETION:
402 		return 4;
403 	case FI_THREAD_DOMAIN:
404 		return 5;
405 	case FI_THREAD_UNSPEC:
406 		return 6;
407 	default:
408 		return -1;
409 	}
410 }
411 
412 /*
413  * Progress models ranked by order of automation.
414  */
fi_progress_level(enum fi_progress progress_model)415 static int fi_progress_level(enum fi_progress progress_model)
416 {
417 	switch (progress_model) {
418 	case FI_PROGRESS_AUTO:
419 		return 1;
420 	case FI_PROGRESS_MANUAL:
421 		return 2;
422 	case FI_PROGRESS_UNSPEC:
423 		return 3;
424 	default:
425 		return -1;
426 	}
427 }
428 
429 /*
430  * Resource management models ranked by order of enablement.
431  */
fi_resource_mgmt_level(enum fi_resource_mgmt rm_model)432 static int fi_resource_mgmt_level(enum fi_resource_mgmt rm_model)
433 {
434 	switch (rm_model) {
435 	case FI_RM_ENABLED:
436 		return 1;
437 	case FI_RM_DISABLED:
438 		return 2;
439 	case FI_RM_UNSPEC:
440 		return 3;
441 	default:
442 		return -1;
443 	}
444 }
445 
446 /*
447  * Remove unneeded MR mode bits based on the requested capability bits.
448  */
ofi_cap_mr_mode(uint64_t info_caps,int mr_mode)449 static int ofi_cap_mr_mode(uint64_t info_caps, int mr_mode)
450 {
451 	if (!ofi_rma_target_allowed(info_caps)) {
452 		if (!(mr_mode & (FI_MR_LOCAL | FI_MR_HMEM)))
453 			return 0;
454 
455 		mr_mode &= ~OFI_MR_MODE_RMA_TARGET;
456 	}
457 
458 	return mr_mode & ~(FI_MR_BASIC | FI_MR_SCALABLE);
459 }
460 
461 /*
462  * Providers should set v1.0 registration modes (FI_MR_BASIC and
463  * FI_MR_SCALABLE) that they support, along with all required modes.
464  */
ofi_check_mr_mode(const struct fi_provider * prov,uint32_t api_version,int prov_mode,const struct fi_info * user_info)465 int ofi_check_mr_mode(const struct fi_provider *prov, uint32_t api_version,
466 		      int prov_mode, const struct fi_info *user_info)
467 {
468 	int user_mode = user_info->domain_attr->mr_mode;
469 	int ret = -FI_ENODATA;
470 
471 	if ((prov_mode & FI_MR_LOCAL) &&
472 	    !((user_info->mode & FI_LOCAL_MR) || (user_mode & FI_MR_LOCAL)))
473 		goto out;
474 
475 	if (FI_VERSION_LT(api_version, FI_VERSION(1, 5))) {
476 		switch (user_mode) {
477 		case FI_MR_UNSPEC:
478 			if (!(prov_mode & (FI_MR_SCALABLE | FI_MR_BASIC)))
479 				goto out;
480 			break;
481 		case FI_MR_BASIC:
482 			if (!(prov_mode & FI_MR_BASIC))
483 				goto out;
484 			break;
485 		case FI_MR_SCALABLE:
486 			if (!(prov_mode & FI_MR_SCALABLE))
487 				goto out;
488 			break;
489 		default:
490 			goto out;
491 		}
492 	} else {
493 		if (user_mode & FI_MR_BASIC) {
494 			if ((user_mode & ~FI_MR_BASIC) ||
495 			    !(prov_mode & FI_MR_BASIC))
496 				goto out;
497 		} else if (user_mode & FI_MR_SCALABLE) {
498 			if ((user_mode & ~FI_MR_SCALABLE) ||
499 			    !(prov_mode & FI_MR_SCALABLE))
500 				goto out;
501 		} else {
502 			prov_mode = ofi_cap_mr_mode(user_info->caps, prov_mode);
503 			if ((user_mode & prov_mode) != prov_mode)
504 				goto out;
505 		}
506 	}
507 
508 	ret = 0;
509 out:
510 	if (ret) {
511 		FI_INFO(prov, FI_LOG_CORE, "Invalid memory registration mode\n");
512 		FI_INFO_MR_MODE(prov, prov_mode, user_mode);
513 	}
514 
515 	return ret;
516 }
517 
ofi_check_domain_attr(const struct fi_provider * prov,uint32_t api_version,const struct fi_domain_attr * prov_attr,const struct fi_info * user_info)518 int ofi_check_domain_attr(const struct fi_provider *prov, uint32_t api_version,
519 			  const struct fi_domain_attr *prov_attr,
520 			  const struct fi_info *user_info)
521 {
522 	const struct fi_domain_attr *user_attr = user_info->domain_attr;
523 
524 	if (fi_thread_level(user_attr->threading) <
525 	    fi_thread_level(prov_attr->threading)) {
526 		FI_INFO(prov, FI_LOG_CORE, "Invalid threading model\n");
527 		return -FI_ENODATA;
528 	}
529 
530 	if (fi_progress_level(user_attr->control_progress) <
531 	    fi_progress_level(prov_attr->control_progress)) {
532 		FI_INFO(prov, FI_LOG_CORE, "Invalid control progress model\n");
533 		return -FI_ENODATA;
534 	}
535 
536 	if (fi_progress_level(user_attr->data_progress) <
537 	    fi_progress_level(prov_attr->data_progress)) {
538 		FI_INFO(prov, FI_LOG_CORE, "Invalid data progress model\n");
539 		return -FI_ENODATA;
540 	}
541 
542 	if (fi_resource_mgmt_level(user_attr->resource_mgmt) <
543 	    fi_resource_mgmt_level(prov_attr->resource_mgmt)) {
544 		FI_INFO(prov, FI_LOG_CORE, "Invalid resource mgmt model\n");
545 		return -FI_ENODATA;
546 	}
547 
548 	if ((prov_attr->av_type != FI_AV_UNSPEC) &&
549 	    (user_attr->av_type != FI_AV_UNSPEC) &&
550 	    (prov_attr->av_type != user_attr->av_type)) {
551 		FI_INFO(prov, FI_LOG_CORE, "Invalid AV type\n");
552 	   	return -FI_ENODATA;
553 	}
554 
555 	if (user_attr->cq_data_size > prov_attr->cq_data_size) {
556 		FI_INFO(prov, FI_LOG_CORE, "CQ data size too large\n");
557 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, cq_data_size);
558 		return -FI_ENODATA;
559 	}
560 
561 	if (ofi_check_mr_mode(prov, api_version, prov_attr->mr_mode, user_info))
562 		return -FI_ENODATA;
563 
564 	if (user_attr->max_ep_stx_ctx > prov_attr->max_ep_stx_ctx) {
565 		FI_INFO(prov, FI_LOG_CORE, "max_ep_stx_ctx greater than supported\n");
566 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, max_ep_stx_ctx);
567 	}
568 
569 	if (user_attr->max_ep_srx_ctx > prov_attr->max_ep_srx_ctx) {
570 		FI_INFO(prov, FI_LOG_CORE, "max_ep_srx_ctx greater than supported\n");
571 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, max_ep_srx_ctx);
572 	}
573 
574 	/* following checks only apply to api 1.5 and beyond */
575 	if (FI_VERSION_LT(api_version, FI_VERSION(1, 5)))
576 		return 0;
577 
578 	if (user_attr->cntr_cnt > prov_attr->cntr_cnt) {
579 		FI_INFO(prov, FI_LOG_CORE, "Cntr count too large\n");
580 		return -FI_ENODATA;
581 	}
582 
583 	if (user_attr->mr_iov_limit > prov_attr->mr_iov_limit) {
584 		FI_INFO(prov, FI_LOG_CORE, "MR iov limit too large\n");
585 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, mr_iov_limit);
586 		return -FI_ENODATA;
587 	}
588 
589 	if (user_attr->caps & ~(prov_attr->caps)) {
590 		FI_INFO(prov, FI_LOG_CORE, "Requested domain caps not supported\n");
591 		FI_INFO_CHECK(prov, prov_attr, user_attr, caps, FI_TYPE_CAPS);
592 		return -FI_ENODATA;
593 	}
594 
595 	if ((user_attr->mode & prov_attr->mode) != prov_attr->mode) {
596 		FI_INFO(prov, FI_LOG_CORE, "Required domain mode missing\n");
597 		FI_INFO_MODE(prov, prov_attr->mode, user_attr->mode);
598 		return -FI_ENODATA;
599 	}
600 
601 	if (user_attr->max_err_data > prov_attr->max_err_data) {
602 		FI_INFO(prov, FI_LOG_CORE, "Max err data too large\n");
603 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, max_err_data);
604 		return -FI_ENODATA;
605 	}
606 
607 	if (user_attr->mr_cnt > prov_attr->mr_cnt) {
608 		FI_INFO(prov, FI_LOG_CORE, "MR count too large\n");
609 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, mr_cnt);
610 		return -FI_ENODATA;
611 	}
612 
613 	return 0;
614 }
615 
ofi_check_ep_type(const struct fi_provider * prov,const struct fi_ep_attr * prov_attr,const struct fi_ep_attr * user_attr)616 int ofi_check_ep_type(const struct fi_provider *prov,
617 		      const struct fi_ep_attr *prov_attr,
618 		      const struct fi_ep_attr *user_attr)
619 {
620 	if ((user_attr->type != FI_EP_UNSPEC) &&
621 	    (prov_attr->type != FI_EP_UNSPEC) &&
622 	    (user_attr->type != prov_attr->type)) {
623 		FI_INFO(prov, FI_LOG_CORE, "unsupported endpoint type\n");
624 		FI_INFO_CHECK(prov, prov_attr, user_attr, type, FI_TYPE_EP_TYPE);
625 		return -FI_ENODATA;
626 	}
627 	return 0;
628 }
629 
ofi_check_ep_attr(const struct util_prov * util_prov,uint32_t api_version,const struct fi_info * prov_info,const struct fi_info * user_info)630 int ofi_check_ep_attr(const struct util_prov *util_prov, uint32_t api_version,
631 		      const struct fi_info *prov_info,
632 		      const struct fi_info *user_info)
633 {
634 	const struct fi_ep_attr *prov_attr = prov_info->ep_attr;
635 	const struct fi_ep_attr *user_attr = user_info->ep_attr;
636 	const struct fi_provider *prov = util_prov->prov;
637 	int ret;
638 
639 	ret = ofi_check_ep_type(prov, prov_attr, user_attr);
640 	if (ret)
641 		return ret;
642 
643 	if ((user_attr->protocol != FI_PROTO_UNSPEC) &&
644 	    (user_attr->protocol != prov_attr->protocol)) {
645 		FI_INFO(prov, FI_LOG_CORE, "Unsupported protocol\n");
646 		FI_INFO_CHECK(prov, prov_attr, user_attr, protocol, FI_TYPE_PROTOCOL);
647 		return -FI_ENODATA;
648 	}
649 
650 	if (user_attr->protocol_version &&
651 	    (user_attr->protocol_version > prov_attr->protocol_version)) {
652 		FI_INFO(prov, FI_LOG_CORE, "Unsupported protocol version\n");
653 		return -FI_ENODATA;
654 	}
655 
656 	if (user_attr->max_msg_size > prov_attr->max_msg_size) {
657 		FI_INFO(prov, FI_LOG_CORE, "Max message size too large\n");
658 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, max_msg_size);
659 		return -FI_ENODATA;
660 	}
661 
662 	if (user_attr->tx_ctx_cnt > prov_info->domain_attr->max_ep_tx_ctx) {
663 		if (user_attr->tx_ctx_cnt == FI_SHARED_CONTEXT) {
664 			if (!prov_info->domain_attr->max_ep_stx_ctx) {
665 				FI_INFO(prov, FI_LOG_CORE,
666 					"Shared tx context not supported\n");
667 				return -FI_ENODATA;
668 			}
669 		} else {
670 			FI_INFO(prov, FI_LOG_CORE,
671 				"Requested tx_ctx_cnt exceeds supported."
672 				" Expected:%zd, Requested%zd\n",
673 				prov_info->domain_attr->max_ep_tx_ctx,
674 				user_attr->tx_ctx_cnt);
675 			return -FI_ENODATA;
676 		}
677 	}
678 
679 	if (user_attr->rx_ctx_cnt > prov_info->domain_attr->max_ep_rx_ctx) {
680 		if (user_attr->rx_ctx_cnt == FI_SHARED_CONTEXT) {
681 			if (!prov_info->domain_attr->max_ep_srx_ctx) {
682 				FI_INFO(prov, FI_LOG_CORE,
683 					"Shared rx context not supported\n");
684 				return -FI_ENODATA;
685 			}
686 		} else {
687 			FI_INFO(prov, FI_LOG_CORE,
688 				"Requested rx_ctx_cnt exceeds supported."
689 				" Expected: %zd, Requested:%zd\n",
690 				prov_info->domain_attr->max_ep_rx_ctx,
691 				user_attr->rx_ctx_cnt);
692 			return -FI_ENODATA;
693 		}
694 	}
695 
696 	if (user_info->caps & (FI_RMA | FI_ATOMIC)) {
697 		if (user_attr->max_order_raw_size >
698 		    prov_attr->max_order_raw_size) {
699 			FI_INFO(prov, FI_LOG_CORE,
700 				"Max order RAW size exceeds supported size\n");
701 			FI_INFO_CHECK_VAL(prov, prov_attr, user_attr,
702 					  max_order_raw_size);
703 			return -FI_ENODATA;
704 		}
705 
706 		if (user_attr->max_order_war_size >
707 		    prov_attr->max_order_war_size) {
708 			FI_INFO(prov, FI_LOG_CORE,
709 				"Max order WAR size exceeds supported size\n");
710 			FI_INFO_CHECK_VAL(prov, prov_attr, user_attr,
711 					  max_order_war_size);
712 			return -FI_ENODATA;
713 		}
714 
715 		if (user_attr->max_order_waw_size >
716 		    prov_attr->max_order_waw_size) {
717 			FI_INFO(prov, FI_LOG_CORE,
718 				"Max order WAW size exceeds supported size\n");
719 			FI_INFO_CHECK_VAL(prov, prov_attr, user_attr,
720 					  max_order_waw_size);
721 			return -FI_ENODATA;
722 		}
723 	}
724 
725 	if (user_attr->auth_key_size &&
726 	    (user_attr->auth_key_size != prov_attr->auth_key_size)) {
727 		FI_INFO(prov, FI_LOG_CORE, "Unsupported authentication size.");
728 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, auth_key_size);
729 		return -FI_ENODATA;
730 	}
731 
732 	return 0;
733 }
734 
ofi_check_rx_attr(const struct fi_provider * prov,const struct fi_info * prov_info,const struct fi_rx_attr * user_attr,uint64_t info_mode)735 int ofi_check_rx_attr(const struct fi_provider *prov,
736 		      const struct fi_info *prov_info,
737 		      const struct fi_rx_attr *user_attr, uint64_t info_mode)
738 {
739 	const struct fi_rx_attr *prov_attr = prov_info->rx_attr;
740 	int rm_enabled = (prov_info->domain_attr->resource_mgmt == FI_RM_ENABLED);
741 
742 	if (user_attr->caps & ~OFI_IGNORED_RX_CAPS)
743 		FI_INFO(prov, FI_LOG_CORE, "Tx only caps ignored in Rx caps\n");
744 
745 	if ((user_attr->caps & ~OFI_IGNORED_RX_CAPS) & ~(prov_attr->caps)) {
746 		FI_INFO(prov, FI_LOG_CORE, "caps not supported\n");
747 		FI_INFO_CHECK(prov, prov_attr, user_attr, caps, FI_TYPE_CAPS);
748 		return -FI_ENODATA;
749 	}
750 
751 	info_mode = user_attr->mode ? user_attr->mode : info_mode;
752 	if ((info_mode & prov_attr->mode) != prov_attr->mode) {
753 		FI_INFO(prov, FI_LOG_CORE, "needed mode not set\n");
754 		FI_INFO_MODE(prov, prov_attr->mode, user_attr->mode);
755 		return -FI_ENODATA;
756 	}
757 
758 	if (user_attr->op_flags & ~(prov_attr->op_flags)) {
759 		FI_INFO(prov, FI_LOG_CORE, "op_flags not supported\n");
760 		FI_INFO_CHECK(prov, prov_attr, user_attr, op_flags,
761 			     FI_TYPE_OP_FLAGS);
762 		return -FI_ENODATA;
763 	}
764 
765 	if (user_attr->msg_order & ~(prov_attr->msg_order)) {
766 		FI_INFO(prov, FI_LOG_CORE, "msg_order not supported\n");
767 		FI_INFO_CHECK(prov, prov_attr, user_attr, msg_order,
768 			     FI_TYPE_MSG_ORDER);
769 		return -FI_ENODATA;
770 	}
771 
772 	if (user_attr->comp_order & ~(prov_attr->comp_order)) {
773 		FI_INFO(prov, FI_LOG_CORE, "comp_order not supported\n");
774 		FI_INFO_CHECK(prov, prov_attr, user_attr, comp_order,
775 			     FI_TYPE_MSG_ORDER);
776 		return -FI_ENODATA;
777 	}
778 
779 	if (user_attr->total_buffered_recv > prov_attr->total_buffered_recv) {
780 		FI_INFO(prov, FI_LOG_CORE, "total_buffered_recv too large\n");
781 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr,
782 				  total_buffered_recv);
783 		return -FI_ENODATA;
784 	}
785 
786 	if (user_attr->size > prov_attr->size) {
787 		FI_INFO(prov, FI_LOG_CORE, "size is greater than supported\n");
788 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, size);
789 		return -FI_ENODATA;
790 	}
791 
792 	if (user_attr->iov_limit > prov_attr->iov_limit) {
793 		FI_INFO(prov, FI_LOG_CORE, "iov_limit too large\n");
794 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, iov_limit);
795 		return -FI_ENODATA;
796 	}
797 
798 	if (!rm_enabled &&
799 	    user_attr->total_buffered_recv > prov_attr->total_buffered_recv) {
800 		/* Just log a notification, but ignore the value */
801 		FI_INFO(prov, FI_LOG_CORE,
802 			"Total buffered recv size exceeds supported size\n");
803 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr,
804 				  total_buffered_recv);
805 	}
806 
807 	return 0;
808 }
809 
ofi_check_attr_subset(const struct fi_provider * prov,uint64_t base_caps,uint64_t requested_caps)810 int ofi_check_attr_subset(const struct fi_provider *prov,
811 		uint64_t base_caps, uint64_t requested_caps)
812 {
813 	uint64_t expanded_caps;
814 
815 	expanded_caps = base_caps;
816 	if (base_caps & (FI_MSG | FI_TAGGED)) {
817 		if (!(base_caps & OFI_MSG_DIRECTION_CAPS))
818 			expanded_caps |= OFI_MSG_DIRECTION_CAPS;
819 	}
820 	if (base_caps & (FI_RMA | FI_ATOMIC)) {
821 		if (!(base_caps & OFI_RMA_DIRECTION_CAPS))
822 			expanded_caps |= OFI_RMA_DIRECTION_CAPS;
823 	}
824 
825 	if (~expanded_caps & requested_caps) {
826 		FI_INFO(prov, FI_LOG_CORE,
827 			"requested caps not subset of base endpoint caps\n");
828 		FI_INFO_FIELD(prov, expanded_caps, requested_caps,
829 			"Supported", "Requested", FI_TYPE_CAPS);
830 		return -FI_ENODATA;
831 	}
832 
833 	return 0;
834 }
835 
ofi_check_tx_attr(const struct fi_provider * prov,const struct fi_tx_attr * prov_attr,const struct fi_tx_attr * user_attr,uint64_t info_mode)836 int ofi_check_tx_attr(const struct fi_provider *prov,
837 		      const struct fi_tx_attr *prov_attr,
838 		      const struct fi_tx_attr *user_attr, uint64_t info_mode)
839 {
840 	if (user_attr->caps & ~OFI_IGNORED_TX_CAPS)
841 		FI_INFO(prov, FI_LOG_CORE, "Rx only caps ignored in Tx caps\n");
842 
843 	if ((user_attr->caps & ~OFI_IGNORED_TX_CAPS) & ~(prov_attr->caps)) {
844 		FI_INFO(prov, FI_LOG_CORE, "caps not supported\n");
845 		FI_INFO_CHECK(prov, prov_attr, user_attr, caps, FI_TYPE_CAPS);
846 		return -FI_ENODATA;
847 	}
848 
849 	info_mode = user_attr->mode ? user_attr->mode : info_mode;
850 	if ((info_mode & prov_attr->mode) != prov_attr->mode) {
851 		FI_INFO(prov, FI_LOG_CORE, "needed mode not set\n");
852 		FI_INFO_MODE(prov, prov_attr->mode, user_attr->mode);
853 		return -FI_ENODATA;
854 	}
855 
856 	if (user_attr->op_flags & ~(prov_attr->op_flags)) {
857 		FI_INFO(prov, FI_LOG_CORE, "op_flags not supported\n");
858 		FI_INFO_CHECK(prov, prov_attr, user_attr, op_flags,
859 			     FI_TYPE_OP_FLAGS);
860 		return -FI_ENODATA;
861 	}
862 
863 	if (user_attr->msg_order & ~(prov_attr->msg_order)) {
864 		FI_INFO(prov, FI_LOG_CORE, "msg_order not supported\n");
865 		FI_INFO_CHECK(prov, prov_attr, user_attr, msg_order,
866 			     FI_TYPE_MSG_ORDER);
867 		return -FI_ENODATA;
868 	}
869 
870 	if (user_attr->comp_order & ~(prov_attr->comp_order)) {
871 		FI_INFO(prov, FI_LOG_CORE, "comp_order not supported\n");
872 		FI_INFO_CHECK(prov, prov_attr, user_attr, comp_order,
873 			     FI_TYPE_MSG_ORDER);
874 		return -FI_ENODATA;
875 	}
876 
877 	if (user_attr->inject_size > prov_attr->inject_size) {
878 		FI_INFO(prov, FI_LOG_CORE, "inject_size too large\n");
879 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, inject_size);
880 		return -FI_ENODATA;
881 	}
882 
883 	if (user_attr->size > prov_attr->size) {
884 		FI_INFO(prov, FI_LOG_CORE, "size is greater than supported\n");
885 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, size);
886 		return -FI_ENODATA;
887 	}
888 
889 	if (user_attr->iov_limit > prov_attr->iov_limit) {
890 		FI_INFO(prov, FI_LOG_CORE, "iov_limit too large\n");
891 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, iov_limit);
892 		return -FI_ENODATA;
893 	}
894 
895 	if (user_attr->rma_iov_limit > prov_attr->rma_iov_limit) {
896 		FI_INFO(prov, FI_LOG_CORE, "rma_iov_limit too large\n");
897 		FI_INFO_CHECK_VAL(prov, prov_attr, user_attr, rma_iov_limit);
898 		return -FI_ENODATA;
899 	}
900 
901 	return 0;
902 }
903 
904 /* Use if there are multiple fi_info in the provider:
905  * check provider's info */
ofi_prov_check_info(const struct util_prov * util_prov,uint32_t api_version,const struct fi_info * user_info)906 int ofi_prov_check_info(const struct util_prov *util_prov,
907 			uint32_t api_version,
908 			const struct fi_info *user_info)
909 {
910 	const struct fi_info *prov_info = util_prov->info;
911 	size_t success_info = 0;
912 	int ret;
913 
914 	if (!user_info)
915 		return FI_SUCCESS;
916 
917 	for ( ; prov_info; prov_info = prov_info->next) {
918 		ret = ofi_check_info(util_prov, prov_info,
919 				     api_version, user_info);
920 		if (!ret)
921 			success_info++;
922 	}
923 
924 	return (!success_info ? -FI_ENODATA : FI_SUCCESS);
925 }
926 
927 /* Use if there are multiple fi_info in the provider:
928  * check and duplicate provider's info */
ofi_prov_check_dup_info(const struct util_prov * util_prov,uint32_t api_version,const struct fi_info * user_info,struct fi_info ** info)929 int ofi_prov_check_dup_info(const struct util_prov *util_prov,
930 			    uint32_t api_version,
931 			    const struct fi_info *user_info,
932 			    struct fi_info **info)
933 {
934 	const struct fi_info *prov_info = util_prov->info;
935 	const struct fi_provider *prov = util_prov->prov;
936 	struct fi_info *fi, *tail;
937 	int ret;
938 
939 	if (!info)
940 		return -FI_EINVAL;
941 
942 	*info = tail = NULL;
943 
944 	for ( ; prov_info; prov_info = prov_info->next) {
945 		ret = ofi_check_info(util_prov, prov_info,
946 				     api_version, user_info);
947 	    	if (ret)
948 			continue;
949 		if (!(fi = fi_dupinfo(prov_info))) {
950 			ret = -FI_ENOMEM;
951 			goto err;
952 		}
953 		if (!*info)
954 			*info = fi;
955 		else
956 			tail->next = fi;
957 		tail = fi;
958 	}
959 
960 	return !*info ? -FI_ENODATA : FI_SUCCESS;
961 err:
962 	fi_freeinfo(*info);
963 	FI_INFO(prov, FI_LOG_CORE,
964 		"cannot copy info\n");
965 	return ret;
966 }
967 
968 /* Use if there is only single fi_info in the provider */
ofi_check_info(const struct util_prov * util_prov,const struct fi_info * prov_info,uint32_t api_version,const struct fi_info * user_info)969 int ofi_check_info(const struct util_prov *util_prov,
970 		   const struct fi_info *prov_info, uint32_t api_version,
971 		   const struct fi_info *user_info)
972 {
973 	const struct fi_provider *prov = util_prov->prov;
974 	uint64_t prov_mode;
975 	int ret;
976 
977 	if (!user_info)
978 		return 0;
979 
980 	/* Check oft-used endpoint type attribute first to avoid any other
981 	 * unnecessary check */
982 	if (user_info->ep_attr) {
983 		ret = ofi_check_ep_type(prov, prov_info->ep_attr,
984 					user_info->ep_attr);
985 		if (ret)
986 			return ret;
987 	}
988 
989 	if (user_info->caps & ~(prov_info->caps)) {
990 		FI_INFO(prov, FI_LOG_CORE, "Unsupported capabilities\n");
991 		FI_INFO_CHECK(prov, prov_info, user_info, caps, FI_TYPE_CAPS);
992 		return -FI_ENODATA;
993 	}
994 
995 	prov_mode = ofi_mr_get_prov_mode(api_version, user_info, prov_info);
996 
997 	if ((user_info->mode & prov_mode) != prov_mode) {
998 		FI_INFO(prov, FI_LOG_CORE, "needed mode not set\n");
999 		FI_INFO_MODE(prov, prov_mode, user_info->mode);
1000 		return -FI_ENODATA;
1001 	}
1002 
1003 	if (!fi_valid_addr_format(prov_info->addr_format,
1004 				  user_info->addr_format)) {
1005 		FI_INFO(prov, FI_LOG_CORE, "address format not supported\n");
1006 		FI_INFO_CHECK(prov, prov_info, user_info, addr_format,
1007 			      FI_TYPE_ADDR_FORMAT);
1008 		return -FI_ENODATA;
1009 	}
1010 
1011 	if (user_info->fabric_attr) {
1012 		ret = ofi_check_fabric_attr(prov, prov_info->fabric_attr,
1013 					    user_info->fabric_attr);
1014 		if (ret)
1015 			return ret;
1016 	}
1017 
1018 	if (user_info->domain_attr) {
1019 		ret = ofi_check_domain_attr(prov, api_version,
1020 					    prov_info->domain_attr,
1021 					    user_info);
1022 		if (ret)
1023 			return ret;
1024 	}
1025 
1026 	if (user_info->ep_attr) {
1027 		ret = ofi_check_ep_attr(util_prov, api_version,
1028 					prov_info, user_info);
1029 		if (ret)
1030 			return ret;
1031 	}
1032 
1033 	if (user_info->rx_attr) {
1034 		ret = ofi_check_rx_attr(prov, prov_info,
1035 					user_info->rx_attr, user_info->mode);
1036 		if (ret)
1037 			return ret;
1038 	}
1039 
1040 	if (user_info->tx_attr) {
1041 		ret = ofi_check_tx_attr(prov, prov_info->tx_attr,
1042 					user_info->tx_attr, user_info->mode);
1043 		if (ret)
1044 			return ret;
1045 	}
1046 	return 0;
1047 }
1048 
ofi_get_caps(uint64_t info_caps,uint64_t hint_caps,uint64_t attr_caps)1049 static uint64_t ofi_get_caps(uint64_t info_caps, uint64_t hint_caps,
1050 			    uint64_t attr_caps)
1051 {
1052 	uint64_t caps;
1053 
1054 	if (!hint_caps) {
1055 		caps = (info_caps & attr_caps & FI_PRIMARY_CAPS) |
1056 		       (attr_caps & FI_SECONDARY_CAPS);
1057 	} else {
1058 		caps = (hint_caps & FI_PRIMARY_CAPS) |
1059 		       (attr_caps & FI_SECONDARY_CAPS);
1060 	}
1061 
1062 	if (caps & (FI_MSG | FI_TAGGED) && !(caps & OFI_MSG_DIRECTION_CAPS))
1063 		caps |= (attr_caps & OFI_MSG_DIRECTION_CAPS);
1064 	if (caps & (FI_RMA | FI_ATOMICS) && !(caps & OFI_RMA_DIRECTION_CAPS))
1065 		caps |= (attr_caps & OFI_RMA_DIRECTION_CAPS);
1066 
1067 	return caps;
1068 }
1069 
fi_alter_domain_attr(struct fi_domain_attr * attr,const struct fi_domain_attr * hints,uint64_t info_caps,uint32_t api_version)1070 static void fi_alter_domain_attr(struct fi_domain_attr *attr,
1071 				 const struct fi_domain_attr *hints,
1072 				 uint64_t info_caps, uint32_t api_version)
1073 {
1074 	int hints_mr_mode;
1075 
1076 	hints_mr_mode = hints ? hints->mr_mode : 0;
1077 	if (hints_mr_mode & (FI_MR_BASIC | FI_MR_SCALABLE)) {
1078 		attr->mr_mode = hints_mr_mode;
1079 	} else if (FI_VERSION_LT(api_version, FI_VERSION(1, 5))) {
1080 		attr->mr_mode = (attr->mr_mode && attr->mr_mode != FI_MR_SCALABLE) ?
1081 				FI_MR_BASIC : FI_MR_SCALABLE;
1082 	} else {
1083 		if ((hints_mr_mode & attr->mr_mode) != attr->mr_mode) {
1084 			attr->mr_mode = ofi_cap_mr_mode(info_caps,
1085 						attr->mr_mode & hints_mr_mode);
1086 		}
1087 	}
1088 
1089 	attr->caps = ofi_get_caps(info_caps, hints ? hints->caps : 0, attr->caps);
1090 	if (!hints)
1091 		return;
1092 
1093 	if (hints->threading)
1094 		attr->threading = hints->threading;
1095 	if (hints->control_progress)
1096 		attr->control_progress = hints->control_progress;
1097 	if (hints->data_progress)
1098 		attr->data_progress = hints->data_progress;
1099 	if (hints->av_type)
1100 		attr->av_type = hints->av_type;
1101 }
1102 
fi_alter_ep_attr(struct fi_ep_attr * attr,const struct fi_ep_attr * hints,uint64_t info_caps)1103 static void fi_alter_ep_attr(struct fi_ep_attr *attr,
1104 			     const struct fi_ep_attr *hints,
1105 			     uint64_t info_caps)
1106 {
1107 	if (!hints)
1108 		return;
1109 
1110 	if (info_caps & (FI_RMA | FI_ATOMIC)) {
1111 		if (hints->max_order_raw_size)
1112 			attr->max_order_raw_size = hints->max_order_raw_size;
1113 		if (hints->max_order_war_size)
1114 			attr->max_order_war_size = hints->max_order_war_size;
1115 		if (hints->max_order_waw_size)
1116 			attr->max_order_waw_size = hints->max_order_waw_size;
1117 	}
1118 	if (hints->tx_ctx_cnt)
1119 		attr->tx_ctx_cnt = hints->tx_ctx_cnt;
1120 	if (hints->rx_ctx_cnt)
1121 		attr->rx_ctx_cnt = hints->rx_ctx_cnt;
1122 }
1123 
fi_alter_rx_attr(struct fi_rx_attr * attr,const struct fi_rx_attr * hints,uint64_t info_caps)1124 static void fi_alter_rx_attr(struct fi_rx_attr *attr,
1125 			     const struct fi_rx_attr *hints,
1126 			     uint64_t info_caps)
1127 {
1128 	attr->caps = ofi_get_caps(info_caps, hints ? hints->caps : 0, attr->caps);
1129 	if (!hints)
1130 		return;
1131 
1132 	attr->op_flags = hints->op_flags;
1133 	attr->total_buffered_recv = hints->total_buffered_recv;
1134 	if (hints->size)
1135 		attr->size = hints->size;
1136 	if (hints->iov_limit)
1137 		attr->iov_limit = hints->iov_limit;
1138 }
1139 
fi_alter_tx_attr(struct fi_tx_attr * attr,const struct fi_tx_attr * hints,uint64_t info_caps)1140 static void fi_alter_tx_attr(struct fi_tx_attr *attr,
1141 			     const struct fi_tx_attr *hints,
1142 			     uint64_t info_caps)
1143 {
1144 	attr->caps = ofi_get_caps(info_caps, hints ? hints->caps : 0, attr->caps);
1145 	if (!hints)
1146 		return;
1147 
1148 	attr->op_flags = hints->op_flags;
1149 	if (hints->inject_size)
1150 		attr->inject_size = hints->inject_size;
1151 	if (hints->size)
1152 		attr->size = hints->size;
1153 	if (hints->iov_limit)
1154 		attr->iov_limit = hints->iov_limit;
1155 	if (hints->rma_iov_limit)
1156 		attr->rma_iov_limit = hints->rma_iov_limit;
1157 }
1158 
ofi_get_info_caps(const struct fi_info * prov_info,const struct fi_info * user_info,uint32_t api_version)1159 static uint64_t ofi_get_info_caps(const struct fi_info *prov_info,
1160 				  const struct fi_info *user_info,
1161 				  uint32_t api_version)
1162 {
1163 	int prov_mode, user_mode;
1164 	uint64_t caps;
1165 
1166 	assert(user_info);
1167 
1168 	caps = ofi_get_caps(prov_info->caps, user_info->caps, prov_info->caps);
1169 
1170 	prov_mode = prov_info->domain_attr->mr_mode;
1171 
1172 	if (!ofi_rma_target_allowed(caps) ||
1173 	    !(prov_mode & OFI_MR_MODE_RMA_TARGET))
1174 		return caps;
1175 
1176 	if (!user_info->domain_attr)
1177 		goto trim_caps;
1178 
1179 	user_mode = user_info->domain_attr->mr_mode;
1180 
1181 	if ((FI_VERSION_LT(api_version, FI_VERSION(1,5)) &&
1182 	    (user_mode == FI_MR_UNSPEC)) ||
1183 	    (user_mode == FI_MR_BASIC) ||
1184 	    ((user_mode & prov_mode & OFI_MR_MODE_RMA_TARGET) ==
1185 	     (prov_mode & OFI_MR_MODE_RMA_TARGET)))
1186 		return caps;
1187 
1188 trim_caps:
1189 	return caps & ~(FI_REMOTE_WRITE | FI_REMOTE_READ);
1190 }
1191 
1192 /*
1193  * Alter the returned fi_info based on the user hints.  We assume that
1194  * the hints have been validated and the starting fi_info is properly
1195  * configured by the provider.
1196  */
ofi_alter_info(struct fi_info * info,const struct fi_info * hints,uint32_t api_version)1197 void ofi_alter_info(struct fi_info *info, const struct fi_info *hints,
1198 		    uint32_t api_version)
1199 {
1200 	if (!hints)
1201 		return;
1202 
1203 	for (; info; info = info->next) {
1204 		/* This should stay before call to fi_alter_domain_attr as
1205 		 * the checks depend on unmodified provider mr_mode attr */
1206 		info->caps = ofi_get_info_caps(info, hints, api_version);
1207 
1208 		if ((info->domain_attr->mr_mode & FI_MR_LOCAL) &&
1209 		    (FI_VERSION_LT(api_version, FI_VERSION(1, 5)) ||
1210 		     (hints && hints->domain_attr &&
1211 		      (hints->domain_attr->mr_mode & (FI_MR_BASIC | FI_MR_SCALABLE)))))
1212 			info->mode |= FI_LOCAL_MR;
1213 
1214 		info->handle = hints->handle;
1215 
1216 		fi_alter_domain_attr(info->domain_attr, hints->domain_attr,
1217 				     info->caps, api_version);
1218 		fi_alter_ep_attr(info->ep_attr, hints->ep_attr, info->caps);
1219 		fi_alter_rx_attr(info->rx_attr, hints->rx_attr, info->caps);
1220 		fi_alter_tx_attr(info->tx_attr, hints->tx_attr, info->caps);
1221 	}
1222 }
1223