1 /*
2  * Copyright (c) 2015-2017 Cray Inc.  All rights reserved.
3  * Copyright (c) 2015-2017 Los Alamos National Security, LLC. 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 <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #include "gnix_cm.h"
40 #include "gnix.h"
41 #include "gnix_util.h"
42 #include "gnix_nic.h"
43 #include "gnix_cm_nic.h"
44 #include "gnix_nameserver.h"
45 #include "gnix_eq.h"
46 #include "gnix_vc.h"
47 #include "gnix_av.h"
48 
49 struct fi_ops gnix_pep_fi_ops;
50 struct fi_ops_ep gnix_pep_ops_ep;
51 struct fi_ops_cm gnix_pep_ops_cm;
52 
_gnix_ep_name_to_str(struct gnix_ep_name * ep_name,char ** out_buf)53 int _gnix_ep_name_to_str(struct gnix_ep_name *ep_name, char **out_buf)
54 {
55 	char *str;
56 	size_t len = GNIX_FI_ADDR_STR_LEN;
57 
58 	GNIX_TRACE(FI_LOG_TRACE, "\n");
59 
60 	if (*out_buf == NULL) {
61 		str = calloc(len, sizeof(char));
62 		if (str == NULL) {
63 			GNIX_WARN(FI_LOG_FABRIC, fi_strerror(FI_ENOMEM));
64 			return -FI_ENOMEM;
65 		}
66 	} else {
67 		str = *out_buf;
68 	}
69 
70 	/* Convert raw address info to string */
71 	snprintf(str, len, "gni;NONE;NONE;%04i;0x%08" PRIx32 ";0x%08" PRIx32
72 		";%02i;0x%06" PRIx32 ";0x%08" PRIx32 ";%02i",
73 		 GNIX_AV_STR_ADDR_VERSION,
74 		 ep_name->gnix_addr.device_addr,
75 		 ep_name->gnix_addr.cdm_id,
76 		 ep_name->name_type,
77 		 ep_name->cm_nic_cdm_id,
78 		 ep_name->cookie,
79 		 ep_name->rx_ctx_cnt);
80 
81 	return FI_SUCCESS;
82 }
83 
_gnix_ep_name_from_str(const char * addr,struct gnix_ep_name * resolved_addr)84 int _gnix_ep_name_from_str(const char *addr,
85 			    struct gnix_ep_name *resolved_addr)
86 {
87 	char *tok, *endptr;
88 	int ret;
89 	struct gnix_ep_name ep_name;
90 	long tok_val;
91 	char *dup_addr;
92 
93 	GNIX_TRACE(FI_LOG_TRACE, "\n");
94 
95 	if (!addr || !resolved_addr) {
96 		GNIX_WARN(FI_LOG_WARN, "NULL parameter in "
97 			"__gnix_resolved_name_from_str");
98 		return -FI_EINVAL;
99 	}
100 
101 	dup_addr = strdup(addr);
102 	if (!dup_addr) {
103 		return -FI_ENOMEM;
104 	}
105 
106 	tok = strtok(dup_addr, ";");
107 	if (!tok) {
108 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
109 		return -FI_EINVAL;
110 	}
111 
112 	ret = memcmp(tok, "gni", 3);
113 	if (ret) {
114 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
115 		free(dup_addr);
116 		return -FI_EINVAL;
117 	}
118 
119 	tok = strtok(NULL, ";");/*node*/
120 	if (!tok) {
121 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
122 		free(dup_addr);
123 		return -FI_EINVAL;
124 	}
125 
126 	tok = strtok(NULL, ";");/*service*/
127 	if (!tok) {
128 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
129 		free(dup_addr);
130 		return -FI_EINVAL;
131 	}
132 
133 	tok = strtok(NULL, ";");/*GNIX_AV_STR_ADDR_VERSION*/
134 	if (!tok) {
135 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
136 		free(dup_addr);
137 		return -FI_EINVAL;
138 	}
139 
140 	/*device_addr*/
141 	tok = strtok(NULL, ";");
142 	if (!tok) {
143 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
144 		free(dup_addr);
145 		return -FI_EINVAL;
146 	}
147 	tok_val = strtol(tok, &endptr, 16);
148 	if (*endptr) {
149 		GNIX_WARN(FI_LOG_WARN, "Invalid device_addr.\n");
150 		free(dup_addr);
151 		return -FI_EINVAL;
152 	}
153 	ep_name.gnix_addr.device_addr = (uint32_t) tok_val;
154 
155 	/*cdm_id*/
156 	tok = strtok(NULL, ";");
157 	if (!tok) {
158 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
159 		free(dup_addr);
160 		return -FI_EINVAL;
161 	}
162 	tok_val = strtol(tok, &endptr, 16);
163 	if (*endptr) {
164 		GNIX_WARN(FI_LOG_WARN, "Invalid cdm_id.\n");
165 		free(dup_addr);
166 		return -FI_EINVAL;
167 	}
168 	ep_name.gnix_addr.cdm_id = (uint32_t) tok_val;
169 
170 	/*name_type*/
171 	tok = strtok(NULL, ";");
172 	if (!tok) {
173 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
174 		free(dup_addr);
175 		return -FI_EINVAL;
176 	}
177 	tok_val = strtol(tok, &endptr, 10);
178 	if (*endptr) {
179 		GNIX_WARN(FI_LOG_WARN, "Invalid name_type.\n");
180 		free(dup_addr);
181 		return -FI_EINVAL;
182 	}
183 	ep_name.name_type = (uint32_t) tok_val;
184 
185 	/*cm_nic_cdm_id*/
186 	tok = strtok(NULL, ";");
187 	if (!tok) {
188 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
189 		free(dup_addr);
190 		return -FI_EINVAL;
191 	}
192 	tok_val = strtol(tok, &endptr, 16);
193 	if (*endptr) {
194 		GNIX_WARN(FI_LOG_WARN, "Invalid cm_nic_cdm_id.\n");
195 		free(dup_addr);
196 		return -FI_EINVAL;
197 	}
198 	ep_name.cm_nic_cdm_id = (uint32_t) tok_val;
199 
200 	/*cookie*/
201 	tok = strtok(NULL, ";");
202 	if (!tok) {
203 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
204 		free(dup_addr);
205 		return -FI_EINVAL;
206 	}
207 	tok_val = strtol(tok, &endptr, 16);
208 	if (*endptr) {
209 		GNIX_WARN(FI_LOG_WARN, "Invalid cookie.\n");
210 		free(dup_addr);
211 		return -FI_EINVAL;
212 	}
213 	ep_name.cookie = (uint32_t) tok_val;
214 
215 	/*rx_ctx_cnt*/
216 	tok = strtok(NULL, ";");
217 	if (!tok) {
218 		GNIX_WARN(FI_LOG_WARN, "Invalid address.\n");
219 		free(dup_addr);
220 		return -FI_EINVAL;
221 	}
222 	tok_val = strtol(tok, &endptr, 10);
223 	if (*endptr) {
224 		GNIX_WARN(FI_LOG_WARN, "Invalid rx_ctx_cnt.\n");
225 		free(dup_addr);
226 		return -FI_EINVAL;
227 	}
228 	ep_name.rx_ctx_cnt = (uint32_t) tok_val;
229 
230 	*resolved_addr = ep_name;
231 	free(dup_addr);
232 
233 	return FI_SUCCESS;
234 }
235 
236 /******************************************************************************
237  *
238  * Common CM handling (supported for all types of endpoints).
239  *
240  *****************************************************************************/
241 
242 /**
243  * Retrieve the local endpoint address.
244  *
245  * addrlen: Should indicate the size of the addr buffer. On output will contain
246  *     the size necessary to copy the proper address structure.
247  *
248  * addr: Pointer to memory that will contain the address structure. Should be
249  *     allocated and of size addrlen. If addrlen is less than necessary to copy
250  *     the proper address structure then addr will contain a truncated address.
251  *     Depending on what hints were used during setup, addr will either be in
252  *     the FI_ADDR_STR or FI_ADDR_GNI format.
253  *
254  * return: FI_SUCCESS or negative error value.
255  */
gnix_getname(fid_t fid,void * addr,size_t * addrlen)256 DIRECT_FN STATIC int gnix_getname(fid_t fid, void *addr, size_t *addrlen)
257 {
258 	struct gnix_fid_ep *ep = NULL;
259 	struct gnix_fid_sep *sep = NULL;
260 	struct gnix_fid_pep *pep = NULL;
261 	size_t len = 0, cpylen;
262 	bool is_fi_addr_str;
263 	struct fi_info *info;
264 	struct gnix_ep_name *ep_name;
265 	int ret;
266 
267 	if (OFI_UNLIKELY(addrlen == NULL)) {
268 		GNIX_INFO(FI_LOG_EP_CTRL, "parameter \"addrlen\" is NULL in "
269 			"gnix_getname\n");
270 		return -FI_EINVAL;
271 	}
272 
273 	switch (fid->fclass) {
274 	case FI_CLASS_EP:
275 		ep = container_of(fid, struct gnix_fid_ep, ep_fid.fid);
276 		info = ep->info;
277 		ep_name = &ep->src_addr;
278 		break;
279 	case FI_CLASS_SEP:
280 		sep = container_of(fid, struct gnix_fid_sep, ep_fid);
281 		info = sep->info;
282 		ep_name = &sep->my_name;
283 		break;
284 	case FI_CLASS_PEP:
285 		pep = container_of(fid, struct gnix_fid_pep,
286 				   pep_fid.fid);
287 		info = pep->info;
288 		ep_name = &pep->src_addr;
289 		break;
290 	default:
291 		GNIX_INFO(FI_LOG_EP_CTRL,
292 			  "Invalid fid class: %d\n",
293 			  fid->fclass);
294 		return -FI_EINVAL;
295 	}
296 
297 	is_fi_addr_str = info->addr_format == FI_ADDR_STR;
298 
299 	if (!addr) {
300 		if (OFI_UNLIKELY(is_fi_addr_str)) {
301 			*addrlen = GNIX_FI_ADDR_STR_LEN;
302 		} else {
303 			*addrlen = sizeof(struct gnix_ep_name);
304 		}
305 
306 		return -FI_ETOOSMALL;
307 	}
308 
309 	if (OFI_UNLIKELY(is_fi_addr_str)) {
310 		ret = _gnix_ep_name_to_str(ep_name, (char **) &addr);
311 
312 		if (ret)
313 			return ret;
314 
315 		len = GNIX_FI_ADDR_STR_LEN;
316 		cpylen = MIN(len, *addrlen);
317 	} else {
318 		len = sizeof(struct gnix_ep_name);
319 		cpylen = MIN(len, *addrlen);
320 		memcpy(addr, ep_name, cpylen);
321 	}
322 
323 	*addrlen = len;
324 	return (len == cpylen) ? FI_SUCCESS : -FI_ETOOSMALL;
325 }
326 
gnix_setname(fid_t fid,void * addr,size_t addrlen)327 DIRECT_FN STATIC int gnix_setname(fid_t fid, void *addr, size_t addrlen)
328 {
329 	struct gnix_fid_ep *ep = NULL;
330 	struct gnix_fid_sep *sep = NULL;
331 	struct gnix_fid_pep *pep = NULL;
332 	struct fi_info *info;
333 	struct gnix_ep_name *ep_name;
334 	size_t len;
335 	int ret;
336 
337 	if (OFI_UNLIKELY(addr == NULL)) {
338 		GNIX_INFO(FI_LOG_EP_CTRL, "parameter \"addr\" is NULL in "
339 			"gnix_setname\n");
340 		return -FI_EINVAL;
341 	}
342 
343 	len = sizeof(struct gnix_ep_name);
344 
345 	switch (fid->fclass) {
346 	case FI_CLASS_EP:
347 		ep = container_of(fid, struct gnix_fid_ep, ep_fid.fid);
348 		info = ep->info;
349 		ep_name = &ep->src_addr;
350 		break;
351 	case FI_CLASS_SEP:
352 		sep = container_of(fid, struct gnix_fid_sep, ep_fid);
353 		info = sep->info;
354 		ep_name = &sep->my_name;
355 		break;
356 	case FI_CLASS_PEP:
357 		pep = container_of(fid, struct gnix_fid_pep, pep_fid.fid);
358 		/* TODO: make sure we're unconnected. */
359 		pep->bound = 1;
360 		info = pep->info;
361 		ep_name = &pep->src_addr;
362 		break;
363 	default:
364 		GNIX_INFO(FI_LOG_EP_CTRL, "Invalid fid class: %d\n",
365 			  fid->fclass);
366 		return -FI_EINVAL;
367 	}
368 
369 	if (OFI_UNLIKELY(info->addr_format == FI_ADDR_STR)) {
370 		len = GNIX_FI_ADDR_STR_LEN;
371 
372 		if (addrlen != len)
373 			return -FI_EINVAL;
374 
375 		ret = _gnix_ep_name_from_str((const char *) addr,
376 					     ep_name);
377 
378 		if (ret)
379 			return ret;
380 
381 		return FI_SUCCESS;
382 	}
383 
384 	if (addrlen != len)
385 		return -FI_EINVAL;
386 
387 	memcpy(ep_name, addr, len);
388 
389 	return FI_SUCCESS;
390 }
391 
gnix_getpeer(struct fid_ep * ep,void * addr,size_t * addrlen)392 DIRECT_FN STATIC int gnix_getpeer(struct fid_ep *ep, void *addr,
393 				  size_t *addrlen)
394 {
395 	struct gnix_fid_ep *ep_priv = NULL;
396 	struct gnix_fid_sep *sep_priv = NULL;
397 	struct gnix_ep_name *ep_name = NULL;
398 	size_t len = 0, cpylen = 0;
399 	struct fi_info *info = NULL;
400 	int ret;
401 
402 	if (OFI_UNLIKELY(addrlen == NULL || addr == NULL)) {
403 		GNIX_INFO(FI_LOG_EP_CTRL,
404 			  "parameter is NULL in gnix_getpeer\n");
405 		return -FI_EINVAL;
406 	}
407 
408 	switch (ep->fid.fclass) {
409 	case FI_CLASS_EP:
410 		ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);
411 		info = ep_priv->info;
412 		ep_name = &ep_priv->dest_addr;
413 		break;
414 
415 	case FI_CLASS_SEP:
416 		sep_priv = container_of(ep, struct gnix_fid_sep, ep_fid);
417 		info = sep_priv->info;
418 		ep_name = info->dest_addr;
419 		break;
420 
421 	default:
422 		GNIX_INFO(FI_LOG_EP_CTRL, "Invalid fid class: %d\n",
423 			  ep->fid.fclass);
424 			return -FI_EINVAL;
425 	}
426 
427 	if (info->addr_format == FI_ADDR_STR) {
428 		ret = _gnix_ep_name_to_str(ep_name, (char **) &addr);
429 
430 		if (ret)
431 			return ret;
432 
433 		len = GNIX_FI_ADDR_STR_LEN;
434 		cpylen = MIN(len, *addrlen);
435 	} else {
436 		len = sizeof(struct gnix_ep_name);
437 		cpylen = MIN(len, *addrlen);
438 		memcpy(addr, ep_name, cpylen);
439 	}
440 
441 	*addrlen = len;
442 
443 	return (len == cpylen) ? FI_SUCCESS : -FI_ETOOSMALL;
444 }
445 
446 struct fi_ops_cm gnix_ep_ops_cm = {
447 	.size = sizeof(struct fi_ops_cm),
448 	.setname = gnix_setname,
449 	.getname = gnix_getname,
450 	.getpeer = gnix_getpeer,
451 	.connect = fi_no_connect,
452 	.listen = fi_no_listen,
453 	.accept = fi_no_accept,
454 	.reject = fi_no_reject,
455 	.shutdown = fi_no_shutdown,
456 	.join = fi_no_join,
457 };
458 
459 /******************************************************************************
460  *
461  * FI_EP_MSG endpoint handling
462  *
463  *****************************************************************************/
464 
465 /* Process a connection response on an FI_EP_MSG. */
__gnix_ep_connresp(struct gnix_fid_ep * ep,struct gnix_pep_sock_connresp * resp)466 static int __gnix_ep_connresp(struct gnix_fid_ep *ep,
467 			      struct gnix_pep_sock_connresp *resp)
468 {
469 	int ret = FI_SUCCESS;
470 	struct fi_eq_cm_entry *eq_entry;
471 	int eqe_size;
472 
473 	switch (resp->cmd) {
474 	case GNIX_PEP_SOCK_RESP_ACCEPT:
475 		ep->vc->peer_caps = resp->peer_caps;
476 		ep->vc->peer_key_offset = resp->key_offset;
477 		ep->vc->peer_id = resp->vc_id;
478 
479 		/* Initialize the GNI connection. */
480 		ret = _gnix_vc_smsg_init(ep->vc, resp->vc_id,
481 					 &resp->vc_mbox_attr,
482 					 &resp->cq_irq_mdh);
483 		if (ret != FI_SUCCESS) {
484 			GNIX_WARN(FI_LOG_EP_CTRL,
485 				  "_gnix_vc_smsg_init returned %s\n",
486 				  fi_strerror(-ret));
487 			return ret;
488 		}
489 
490 		ep->vc->conn_state = GNIX_VC_CONNECTED;
491 		ep->conn_state = GNIX_EP_CONNECTED;
492 
493 		/* Notify user that this side is connected. */
494 		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
495 		eq_entry->fid = &ep->ep_fid.fid;
496 
497 		eqe_size = sizeof(*eq_entry) + resp->cm_data_len;
498 		ret = fi_eq_write(&ep->eq->eq_fid, FI_CONNECTED, eq_entry,
499 				  eqe_size, 0);
500 		if (ret != eqe_size) {
501 			GNIX_WARN(FI_LOG_EP_CTRL,
502 				  "fi_eq_write failed, err: %d\n", ret);
503 			return ret;
504 		}
505 
506 		GNIX_DEBUG(FI_LOG_EP_CTRL, "Received conn accept: %p\n", ep);
507 
508 		break;
509 	case GNIX_PEP_SOCK_RESP_REJECT:
510 		/* Undo the connect and generate a failure EQE. */
511 		close(ep->conn_fd);
512 		ep->conn_fd = -1;
513 
514 		_gnix_mbox_free(ep->vc->smsg_mbox);
515 		ep->vc->smsg_mbox = NULL;
516 
517 		_gnix_vc_destroy(ep->vc);
518 		ep->vc = NULL;
519 
520 		ep->conn_state = GNIX_EP_UNCONNECTED;
521 
522 		/* Generate EQE. */
523 		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
524 		eq_entry->fid = &ep->ep_fid.fid;
525 
526 		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
527 		ret = _gnix_eq_write_error(ep->eq, &ep->ep_fid.fid, NULL, 0,
528 					   FI_ECONNREFUSED, FI_ECONNREFUSED,
529 					   &eq_entry->data, resp->cm_data_len);
530 		if (ret != FI_SUCCESS) {
531 			GNIX_WARN(FI_LOG_EP_CTRL,
532 				  "fi_eq_write failed, err: %d\n", ret);
533 			return ret;
534 		}
535 
536 		GNIX_DEBUG(FI_LOG_EP_CTRL, "Conn rejected: %p\n", ep);
537 
538 		break;
539 	default:
540 		GNIX_INFO(FI_LOG_EP_CTRL, "Invalid response command: %d\n",
541 			  resp->cmd);
542 		return -FI_EINVAL;
543 	}
544 
545 	return FI_SUCCESS;
546 }
547 
548 /* Check for a connection response on an FI_EP_MSG. */
_gnix_ep_progress(struct gnix_fid_ep * ep)549 int _gnix_ep_progress(struct gnix_fid_ep *ep)
550 {
551 	int ret, bytes_read, errno_keep;
552 	struct gnix_pep_sock_connresp resp;
553 
554 	/* No lock, fast exit. */
555 	if (ep->conn_state != GNIX_EP_CONNECTING) {
556 		return FI_SUCCESS;
557 	}
558 
559 	COND_ACQUIRE(ep->requires_lock, &ep->vc_lock);
560 
561 	if (ep->conn_state != GNIX_EP_CONNECTING) {
562 		COND_RELEASE(ep->requires_lock, &ep->vc_lock);
563 		return FI_SUCCESS;
564 	}
565 
566 	/* Check for a connection response. */
567 	bytes_read = read(ep->conn_fd, &resp, sizeof(resp));
568 	if (bytes_read >= 0) {
569 		if (bytes_read == sizeof(resp)) {
570 			/* Received response. */
571 			ret = __gnix_ep_connresp(ep, &resp);
572 			if (ret != FI_SUCCESS) {
573 				GNIX_WARN(FI_LOG_EP_CTRL,
574 					  "__gnix_pep_connreq failed, %d\n",
575 					  ret);
576 			}
577 		} else {
578 			errno_keep = errno;
579 			GNIX_FATAL(FI_LOG_EP_CTRL,
580 				   "Unexpected read size: %d err: %s\n",
581 				   bytes_read, strerror(errno_keep));
582 		}
583 	} else if (errno != EAGAIN) {
584 		errno_keep = errno;
585 		GNIX_WARN(FI_LOG_EP_CTRL, "Read error: %s\n",
586 				strerror(errno_keep));
587 	}
588 
589 	COND_RELEASE(ep->requires_lock, &ep->vc_lock);
590 
591 	return FI_SUCCESS;
592 }
593 
gnix_connect(struct fid_ep * ep,const void * addr,const void * param,size_t paramlen)594 DIRECT_FN STATIC int gnix_connect(struct fid_ep *ep, const void *addr,
595 				  const void *param, size_t paramlen)
596 {
597 	int ret, errno_keep;
598 	struct gnix_fid_ep *ep_priv;
599 	struct sockaddr_in saddr;
600 	struct gnix_pep_sock_connreq req;
601 	struct fi_eq_cm_entry *eqe_ptr;
602 	struct gnix_vc *vc;
603 	struct gnix_mbox *mbox = NULL;
604 	struct gnix_av_addr_entry av_entry;
605 
606 	if (!ep || !addr || (paramlen && !param) ||
607 	    paramlen > GNIX_CM_DATA_MAX_SIZE)
608 		return -FI_EINVAL;
609 
610 	ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);
611 
612 	COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock);
613 
614 	if (ep_priv->conn_state != GNIX_EP_UNCONNECTED) {
615 		ret = -FI_EINVAL;
616 		goto err_unlock;
617 	}
618 
619 	ret = _gnix_pe_to_ip(addr, &saddr);
620 	if (ret != FI_SUCCESS) {
621 		GNIX_INFO(FI_LOG_EP_CTRL,
622 			  "Failed to translate gnix_ep_name to IP\n");
623 		goto err_unlock;
624 	}
625 
626 	/* Create new VC without CM data. */
627 	av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr;
628 	av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id;
629 	ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc);
630 	if (ret != FI_SUCCESS) {
631 		GNIX_WARN(FI_LOG_EP_CTRL,
632 			  "Failed to create VC:: %d\n",
633 			  ret);
634 		goto err_unlock;
635 	}
636 	ep_priv->vc = vc;
637 
638 	ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox);
639 	if (ret != FI_SUCCESS) {
640 		GNIX_WARN(FI_LOG_EP_DATA,
641 			  "_gnix_mbox_alloc returned %s\n",
642 			  fi_strerror(-ret));
643 		goto err_mbox_alloc;
644 	}
645 	vc->smsg_mbox = mbox;
646 
647 	ep_priv->conn_fd = socket(AF_INET, SOCK_STREAM, 0);
648 	if (ep_priv->conn_fd < 0) {
649 		errno_keep = errno;
650 		GNIX_WARN(FI_LOG_EP_CTRL,
651 			  "Failed to create connect socket, err: %s\n",
652 			  strerror(errno_keep));
653 		ret = -FI_ENOSPC;
654 		goto err_socket;
655 	}
656 
657 	/* Currently blocks until connected. */
658 	ret = connect(ep_priv->conn_fd, (struct sockaddr *)&saddr,
659 		      sizeof(saddr));
660 	if (ret) {
661 		errno_keep = errno;
662 		GNIX_WARN(FI_LOG_EP_CTRL,
663 			  "Failed to connect, err: %s\n",
664 			  strerror(errno_keep));
665 		ret = -FI_EIO;
666 		goto err_connect;
667 	}
668 
669 	memset(&req, 0, sizeof(req));
670 	req.info = *ep_priv->info;
671 
672 	/* Note addrs are swapped. */
673 	memcpy(&req.dest_addr, (void *)&ep_priv->src_addr,
674 	       sizeof(req.dest_addr));
675 	memcpy(&ep_priv->dest_addr, addr, sizeof(ep_priv->dest_addr));
676 	memcpy(&req.src_addr, addr, sizeof(req.src_addr));
677 
678 	if (ep_priv->info->tx_attr)
679 		req.tx_attr = *ep_priv->info->tx_attr;
680 	if (ep_priv->info->rx_attr)
681 		req.rx_attr = *ep_priv->info->rx_attr;
682 	if (ep_priv->info->ep_attr)
683 		req.ep_attr = *ep_priv->info->ep_attr;
684 	if (ep_priv->info->domain_attr)
685 		req.domain_attr = *ep_priv->info->domain_attr;
686 	if (ep_priv->info->fabric_attr)
687 		req.fabric_attr = *ep_priv->info->fabric_attr;
688 
689 	req.vc_id = vc->vc_id;
690 	req.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
691 	req.vc_mbox_attr.msg_buffer = mbox->base;
692 	req.vc_mbox_attr.buff_size =  vc->ep->nic->mem_per_mbox;
693 	req.vc_mbox_attr.mem_hndl = *mbox->memory_handle;
694 	req.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset;
695 	req.vc_mbox_attr.mbox_maxcredit =
696 			ep_priv->domain->params.mbox_maxcredit;
697 	req.vc_mbox_attr.msg_maxsize = ep_priv->domain->params.mbox_msg_maxsize;
698 	req.cq_irq_mdh = ep_priv->nic->irq_mem_hndl;
699 	req.peer_caps = ep_priv->caps;
700 	req.key_offset = ep_priv->auth_key->key_offset;
701 
702 	req.cm_data_len = paramlen;
703 	if (paramlen) {
704 		eqe_ptr = (struct fi_eq_cm_entry *)req.eqe_buf;
705 		memcpy(eqe_ptr->data, param, paramlen);
706 	}
707 
708 	ret = write(ep_priv->conn_fd, &req, sizeof(req));
709 	if (ret != sizeof(req)) {
710 		errno_keep = errno;
711 		GNIX_WARN(FI_LOG_EP_CTRL,
712 			  "Failed to send req, err: %s\n",
713 			  strerror(errno_keep));
714 		ret = -FI_EIO;
715 		goto err_write;
716 	}
717 	/* set fd to non-blocking now since we can't block within the eq
718 	 * progress system
719 	 */
720 	fi_fd_nonblock(ep_priv->conn_fd);
721 
722 	ep_priv->conn_state = GNIX_EP_CONNECTING;
723 
724 	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);
725 
726 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn req: %p, %s\n",
727 		   ep_priv, inet_ntoa(saddr.sin_addr));
728 
729 	return FI_SUCCESS;
730 
731 err_write:
732 err_connect:
733 	close(ep_priv->conn_fd);
734 	ep_priv->conn_fd = -1;
735 err_socket:
736 	_gnix_mbox_free(ep_priv->vc->smsg_mbox);
737 	ep_priv->vc->smsg_mbox = NULL;
738 err_mbox_alloc:
739 	_gnix_vc_destroy(ep_priv->vc);
740 	ep_priv->vc = NULL;
741 err_unlock:
742 	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);
743 
744 	return ret;
745 }
746 
gnix_accept(struct fid_ep * ep,const void * param,size_t paramlen)747 DIRECT_FN STATIC int gnix_accept(struct fid_ep *ep, const void *param,
748 				 size_t paramlen)
749 {
750 	int ret, errno_keep;
751 	struct gnix_vc *vc;
752 	struct gnix_fid_ep *ep_priv;
753 	struct gnix_pep_sock_conn *conn;
754 	struct gnix_pep_sock_connresp resp;
755 	struct fi_eq_cm_entry eq_entry, *eqe_ptr;
756 	struct gnix_mbox *mbox = NULL;
757 	struct gnix_av_addr_entry av_entry;
758 
759 	if (!ep || (paramlen && !param) || paramlen > GNIX_CM_DATA_MAX_SIZE)
760 		return -FI_EINVAL;
761 
762 	ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);
763 
764 	COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock);
765 
766 	/* Look up and unpack the connection request used to create this EP. */
767 	conn = (struct gnix_pep_sock_conn *)ep_priv->info->handle;
768 	if (!conn || conn->fid.fclass != FI_CLASS_CONNREQ) {
769 		ret = -FI_EINVAL;
770 		goto err_unlock;
771 	}
772 
773 	/* Create new VC without CM data. */
774 	av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr;
775 	av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id;
776 	ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc);
777 	if (ret != FI_SUCCESS) {
778 		GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create VC: %d\n", ret);
779 		goto err_unlock;
780 	}
781 	ep_priv->vc = vc;
782 	ep_priv->vc->peer_caps = conn->req.peer_caps;
783 	ep_priv->vc->peer_key_offset = conn->req.key_offset;
784 	ep_priv->vc->peer_id = conn->req.vc_id;
785 
786 	ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox);
787 	if (ret != FI_SUCCESS) {
788 		GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n",
789 			  fi_strerror(-ret));
790 		goto err_mbox_alloc;
791 	}
792 	vc->smsg_mbox = mbox;
793 
794 	/* Initialize the GNI connection. */
795 	ret = _gnix_vc_smsg_init(vc, conn->req.vc_id,
796 				 &conn->req.vc_mbox_attr,
797 				 &conn->req.cq_irq_mdh);
798 	if (ret != FI_SUCCESS) {
799 		GNIX_WARN(FI_LOG_EP_CTRL,
800 			  "_gnix_vc_smsg_init returned %s\n",
801 			  fi_strerror(-ret));
802 		goto err_smsg_init;
803 	}
804 
805 	vc->conn_state = GNIX_VC_CONNECTED;
806 
807 	/* Send ACK with VC attrs to allow peer to initialize GNI connection. */
808 	resp.cmd = GNIX_PEP_SOCK_RESP_ACCEPT;
809 
810 	resp.vc_id = vc->vc_id;
811 	resp.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
812 	resp.vc_mbox_attr.msg_buffer = mbox->base;
813 	resp.vc_mbox_attr.buff_size =  vc->ep->nic->mem_per_mbox;
814 	resp.vc_mbox_attr.mem_hndl = *mbox->memory_handle;
815 	resp.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset;
816 	resp.vc_mbox_attr.mbox_maxcredit =
817 			ep_priv->domain->params.mbox_maxcredit;
818 	resp.vc_mbox_attr.msg_maxsize =
819 			ep_priv->domain->params.mbox_msg_maxsize;
820 	resp.cq_irq_mdh = ep_priv->nic->irq_mem_hndl;
821 	resp.peer_caps = ep_priv->caps;
822 	resp.key_offset = ep_priv->auth_key->key_offset;
823 
824 	resp.cm_data_len = paramlen;
825 	if (paramlen) {
826 		eqe_ptr = (struct fi_eq_cm_entry *)resp.eqe_buf;
827 		memcpy(eqe_ptr->data, param, paramlen);
828 	}
829 
830 	ret = write(conn->sock_fd, &resp, sizeof(resp));
831 	if (ret != sizeof(resp)) {
832 		errno_keep = errno;
833 		GNIX_WARN(FI_LOG_EP_CTRL,
834 			  "Failed to send resp, err: %s\n",
835 			  strerror(errno_keep));
836 		ret = -FI_EIO;
837 		goto err_write;
838 	}
839 
840 	/* Notify user that this side is connected. */
841 	eq_entry.fid = &ep_priv->ep_fid.fid;
842 
843 	ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_CONNECTED, &eq_entry,
844 			  sizeof(eq_entry), 0);
845 	if (ret != sizeof(eq_entry)) {
846 		GNIX_WARN(FI_LOG_EP_CTRL,
847 			  "fi_eq_write failed, err: %d\n", ret);
848 		goto err_eq_write;
849 	}
850 
851 	/* Free the connection request. */
852 	free(conn);
853 
854 	ep_priv->conn_state = GNIX_EP_CONNECTED;
855 
856 	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);
857 
858 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn accept: %p\n", ep_priv);
859 
860 	return FI_SUCCESS;
861 
862 err_eq_write:
863 err_write:
864 err_smsg_init:
865 	_gnix_mbox_free(ep_priv->vc->smsg_mbox);
866 	ep_priv->vc->smsg_mbox = NULL;
867 err_mbox_alloc:
868 	_gnix_vc_destroy(ep_priv->vc);
869 	ep_priv->vc = NULL;
870 err_unlock:
871 	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);
872 
873 	return ret;
874 }
875 
gnix_shutdown(struct fid_ep * ep,uint64_t flags)876 DIRECT_FN STATIC int gnix_shutdown(struct fid_ep *ep, uint64_t flags)
877 {
878 	int ret;
879 	struct gnix_fid_ep *ep_priv;
880 	struct fi_eq_cm_entry eq_entry = {0};
881 
882 	if (!ep)
883 		return -FI_EINVAL;
884 
885 	ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);
886 
887 	COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock);
888 
889 	eq_entry.fid = &ep_priv->ep_fid.fid;
890 
891 	ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_SHUTDOWN, &eq_entry,
892 			  sizeof(eq_entry), 0);
893 	if (ret != sizeof(eq_entry)) {
894 		GNIX_WARN(FI_LOG_EP_CTRL,
895 			  "fi_eq_write failed, err: %d\n", ret);
896 	} else {
897 		ret = FI_SUCCESS;
898 	}
899 
900 	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);
901 
902 	return ret;
903 }
904 
905 struct fi_ops_cm gnix_ep_msg_ops_cm = {
906 	.size = sizeof(struct fi_ops_cm),
907 	.setname = gnix_setname,
908 	.getname = gnix_getname,
909 	.getpeer = gnix_getpeer,
910 	.connect = gnix_connect,
911 	.listen = fi_no_listen,
912 	.accept = gnix_accept,
913 	.reject = fi_no_reject,
914 	.shutdown = gnix_shutdown,
915 	.join = fi_no_join,
916 };
917 
918 /******************************************************************************
919  *
920  * Passive endpoint handling
921  *
922  *****************************************************************************/
923 
gnix_pep_getopt(fid_t fid,int level,int optname,void * optval,size_t * optlen)924 DIRECT_FN STATIC int gnix_pep_getopt(fid_t fid, int level, int optname,
925 				     void *optval, size_t *optlen)
926 {
927 	if (!fid || !optval || !optlen)
928 		return -FI_EINVAL;
929 	else if (level != FI_OPT_ENDPOINT)
930 		return -FI_ENOPROTOOPT;
931 
932 	switch (optname) {
933 	case FI_OPT_CM_DATA_SIZE:
934 		*(size_t *)optval = GNIX_CM_DATA_MAX_SIZE;
935 		*optlen = sizeof(size_t);
936 		break;
937 	default:
938 		return -FI_ENOPROTOOPT;
939 	}
940 
941 	return 0;
942 }
943 
944 /* Process an incoming connection request at a listening PEP. */
__gnix_pep_connreq(struct gnix_fid_pep * pep,int fd)945 static int __gnix_pep_connreq(struct gnix_fid_pep *pep, int fd)
946 {
947 	int ret;
948 	struct gnix_pep_sock_conn *conn;
949 	struct fi_eq_cm_entry *eq_entry;
950 	int eqe_size;
951 
952 	/* Create and initialize a new connection request. */
953 	conn = calloc(1, sizeof(*conn));
954 	if (!conn) {
955 		GNIX_WARN(FI_LOG_EP_CTRL,
956 			  "Failed to alloc accepted socket conn\n");
957 		return -FI_ENOMEM;
958 	}
959 
960 	conn->fid.fclass = FI_CLASS_CONNREQ;
961 	conn->fid.context = pep;
962 	conn->sock_fd = fd;
963 
964 	/* Pull request data from the listening socket. */
965 	conn->bytes_read += read(fd, &conn->req, sizeof(conn->req));
966 	if (conn->bytes_read != sizeof(conn->req)) {
967 		/* TODO Wait for more bytes. */
968 		GNIX_FATAL(FI_LOG_EP_CTRL, "Unexpected read size\n");
969 	}
970 
971 	conn->req.info.src_addr = &conn->req.src_addr;
972 	conn->req.info.dest_addr = &conn->req.dest_addr;
973 	conn->req.info.tx_attr = &conn->req.tx_attr;
974 	conn->req.info.rx_attr = &conn->req.rx_attr;
975 	conn->req.info.ep_attr = &conn->req.ep_attr;
976 	conn->req.info.domain_attr = &conn->req.domain_attr;
977 	conn->req.info.fabric_attr = &conn->req.fabric_attr;
978 	conn->req.info.domain_attr->name = NULL;
979 	conn->req.info.fabric_attr->name = NULL;
980 	conn->req.info.fabric_attr->prov_name = NULL;
981 
982 	conn->info = &conn->req.info;
983 	conn->info->handle = &conn->fid;
984 
985 	/* Tell user of a new conn req via the EQ. */
986 	eq_entry = (struct fi_eq_cm_entry *)conn->req.eqe_buf;
987 	eq_entry->fid = &pep->pep_fid.fid;
988 	eq_entry->info = fi_dupinfo(conn->info);
989 
990 	eqe_size = sizeof(*eq_entry) + conn->req.cm_data_len;
991 	ret = fi_eq_write(&pep->eq->eq_fid, FI_CONNREQ, eq_entry, eqe_size, 0);
992 	if (ret != eqe_size) {
993 		GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret);
994 		fi_freeinfo(conn->info);
995 		free(conn);
996 		return ret;
997 	}
998 
999 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Added FI_CONNREQ EQE: %p, %p\n",
1000 		   pep->eq, pep);
1001 
1002 	return FI_SUCCESS;
1003 }
1004 
1005 /* Process incoming connection requests on a listening PEP. */
_gnix_pep_progress(struct gnix_fid_pep * pep)1006 int _gnix_pep_progress(struct gnix_fid_pep *pep)
1007 {
1008 	int accept_fd, ret, errno_keep;
1009 
1010 	fastlock_acquire(&pep->lock);
1011 
1012 	accept_fd = accept(pep->listen_fd, NULL, NULL);
1013 	if (accept_fd >= 0) {
1014 		/* New Connection. */
1015 		ret = __gnix_pep_connreq(pep, accept_fd);
1016 		if (ret != FI_SUCCESS) {
1017 			GNIX_WARN(FI_LOG_EP_CTRL,
1018 				  "__gnix_pep_connreq failed, err: %d\n",
1019 				  ret);
1020 		}
1021 	} else if (errno != EAGAIN) {
1022 		errno_keep = errno;
1023 		GNIX_WARN(FI_LOG_EP_CTRL,
1024 			  "(accept) Unexpected errno on listen socket: %s\n",
1025 			  strerror(errno_keep));
1026 	}
1027 
1028 	fastlock_release(&pep->lock);
1029 
1030 	return FI_SUCCESS;
1031 }
1032 
__pep_destruct(void * obj)1033 static void __pep_destruct(void *obj)
1034 {
1035 	struct gnix_fid_pep *pep = (struct gnix_fid_pep *)obj;
1036 
1037 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Destroying PEP: %p\n", pep);
1038 
1039 	fastlock_destroy(&pep->lock);
1040 
1041 	if (pep->listen_fd >= 0)
1042 		close(pep->listen_fd);
1043 
1044 	if (pep->eq) {
1045 		_gnix_eq_poll_obj_rem(pep->eq, &pep->pep_fid.fid);
1046 		_gnix_ref_put(pep->eq);
1047 	}
1048 
1049 	free(pep);
1050 }
1051 
gnix_pep_close(fid_t fid)1052 static int gnix_pep_close(fid_t fid)
1053 {
1054 	int ret = FI_SUCCESS;
1055 	struct gnix_fid_pep *pep;
1056 	int references_held;
1057 
1058 	pep = container_of(fid, struct gnix_fid_pep, pep_fid.fid);
1059 
1060 	references_held = _gnix_ref_put(pep);
1061 	if (references_held)
1062 		GNIX_INFO(FI_LOG_EP_CTRL, "failed to fully close pep due "
1063 			  "to lingering references. references=%i pep=%p\n",
1064 			  references_held, pep);
1065 
1066 	return ret;
1067 }
1068 
gnix_pep_bind(struct fid * fid,struct fid * bfid,uint64_t flags)1069 DIRECT_FN int gnix_pep_bind(struct fid *fid, struct fid *bfid, uint64_t flags)
1070 {
1071 	int ret = FI_SUCCESS;
1072 	struct gnix_fid_pep  *pep;
1073 	struct gnix_fid_eq *eq;
1074 
1075 	if (!fid || !bfid)
1076 		return -FI_EINVAL;
1077 
1078 	pep = container_of(fid, struct gnix_fid_pep, pep_fid.fid);
1079 
1080 	fastlock_acquire(&pep->lock);
1081 
1082 	switch (bfid->fclass) {
1083 	case FI_CLASS_EQ:
1084 		eq = container_of(bfid, struct gnix_fid_eq, eq_fid.fid);
1085 		if (pep->fabric != eq->fabric) {
1086 			ret = -FI_EINVAL;
1087 			break;
1088 		}
1089 
1090 		if (pep->eq) {
1091 			ret = -FI_EINVAL;
1092 			break;
1093 		}
1094 
1095 		pep->eq = eq;
1096 		_gnix_eq_poll_obj_add(eq, &pep->pep_fid.fid);
1097 		_gnix_ref_get(eq);
1098 
1099 		GNIX_DEBUG(FI_LOG_EP_CTRL, "Bound EQ to PEP: %p, %p\n",
1100 			   eq, pep);
1101 		break;
1102 	default:
1103 		ret = -FI_ENOSYS;
1104 		break;
1105 	}
1106 
1107 	fastlock_release(&pep->lock);
1108 
1109 	return ret;
1110 }
1111 
gnix_pep_listen(struct fid_pep * pep)1112 DIRECT_FN int gnix_pep_listen(struct fid_pep *pep)
1113 {
1114 	int ret, errno_keep;
1115 	struct gnix_fid_pep *pep_priv;
1116 	struct sockaddr_in saddr;
1117 	int sockopt = 1;
1118 
1119 	if (!pep)
1120 		return -FI_EINVAL;
1121 
1122 	pep_priv = container_of(pep, struct gnix_fid_pep, pep_fid.fid);
1123 
1124 	fastlock_acquire(&pep_priv->lock);
1125 
1126 	if (!pep_priv->eq) {
1127 		ret = -FI_EINVAL;
1128 		goto err_unlock;
1129 	}
1130 
1131 	pep_priv->listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
1132 	if (pep_priv->listen_fd < 0) {
1133 		errno_keep = errno;
1134 		GNIX_WARN(FI_LOG_EP_CTRL,
1135 			  "Failed to create listening socket, err: %s\n",
1136 			  strerror(errno_keep));
1137 		ret = -FI_ENOSPC;
1138 		goto err_unlock;
1139 	}
1140 
1141 	ret = setsockopt(pep_priv->listen_fd, SOL_SOCKET, SO_REUSEADDR,
1142 			 &sockopt, sizeof(sockopt));
1143 	if (ret < 0) {
1144 		errno_keep = errno;
1145 		GNIX_WARN(FI_LOG_EP_CTRL,
1146 			  "setsockopt(SO_REUSEADDR) failed, err: %s\n",
1147 			  strerror(errno_keep));
1148 	}
1149 
1150 	/* Bind to the ipogif interface using resolved service number as CDM
1151 	 * ID. */
1152 	ret = _gnix_local_ipaddr(&saddr);
1153 	if (ret != FI_SUCCESS) {
1154 		GNIX_WARN(FI_LOG_EP_CTRL, "Failed to find local IP\n");
1155 		ret = -FI_ENOSPC;
1156 		goto err_sock;
1157 	}
1158 
1159 	/* If source addr was not specified, use auto assigned port. */
1160 	if (pep_priv->bound)
1161 		saddr.sin_port = pep_priv->src_addr.gnix_addr.cdm_id;
1162 	else
1163 		saddr.sin_port = 0;
1164 
1165 	ret = bind(pep_priv->listen_fd, &saddr, sizeof(struct sockaddr_in));
1166 	if (ret < 0) {
1167 		errno_keep = errno;
1168 		GNIX_WARN(FI_LOG_EP_CTRL,
1169 			  "Failed to bind listening socket, err: %s\n",
1170 			  strerror(errno_keep));
1171 		ret = -FI_ENOSPC;
1172 		goto err_sock;
1173 	}
1174 
1175 	ret = listen(pep_priv->listen_fd, pep_priv->backlog);
1176 	if (ret < 0) {
1177 		errno_keep = errno;
1178 		GNIX_WARN(FI_LOG_EP_CTRL,
1179 			  "Failed to start listening socket, err: %s\n",
1180 			  strerror(errno_keep));
1181 		ret = -FI_ENOSPC;
1182 		goto err_sock;
1183 	}
1184 
1185 	fastlock_release(&pep_priv->lock);
1186 
1187 	GNIX_DEBUG(FI_LOG_EP_CTRL,
1188 		   "Configured PEP for listening: %p (%s:%d)\n",
1189 		   pep, inet_ntoa(saddr.sin_addr), saddr.sin_port);
1190 
1191 	return FI_SUCCESS;
1192 
1193 err_sock:
1194 	close(pep_priv->listen_fd);
1195 err_unlock:
1196 	fastlock_release(&pep_priv->lock);
1197 	return ret;
1198 }
1199 
1200 __attribute__((unused))
gnix_listen(struct fid_pep * pep)1201 DIRECT_FN STATIC int gnix_listen(struct fid_pep *pep)
1202 {
1203         return -FI_ENOSYS;
1204 }
1205 
gnix_reject(struct fid_pep * pep,fid_t handle,const void * param,size_t paramlen)1206 DIRECT_FN STATIC int gnix_reject(struct fid_pep *pep, fid_t handle,
1207 				 const void *param, size_t paramlen)
1208 {
1209 	struct gnix_fid_pep *pep_priv;
1210 	struct gnix_pep_sock_conn *conn;
1211 	struct gnix_pep_sock_connresp resp;
1212 	struct fi_eq_cm_entry *eqe_ptr;
1213 	int ret;
1214 
1215 	if (!pep)
1216 		return -FI_EINVAL;
1217 
1218 	pep_priv = container_of(pep, struct gnix_fid_pep, pep_fid.fid);
1219 
1220 	fastlock_acquire(&pep_priv->lock);
1221 
1222 	conn = (struct gnix_pep_sock_conn *)handle;
1223 	if (!conn || conn->fid.fclass != FI_CLASS_CONNREQ) {
1224 		fastlock_release(&pep_priv->lock);
1225 		return -FI_EINVAL;
1226 	}
1227 
1228 	resp.cmd = GNIX_PEP_SOCK_RESP_REJECT;
1229 
1230 	resp.cm_data_len = paramlen;
1231 	if (paramlen) {
1232 		eqe_ptr = (struct fi_eq_cm_entry *)resp.eqe_buf;
1233 		memcpy(eqe_ptr->data, param, paramlen);
1234 	}
1235 
1236 	ret = write(conn->sock_fd, &resp, sizeof(resp));
1237 	if (ret != sizeof(resp)) {
1238 		fastlock_release(&pep_priv->lock);
1239 		GNIX_WARN(FI_LOG_EP_CTRL,
1240 			  "Failed to send resp, errno: %d\n",
1241 			  errno);
1242 		return -FI_EIO;
1243 	}
1244 
1245 	close(conn->sock_fd);
1246 	free(conn);
1247 
1248 	fastlock_release(&pep_priv->lock);
1249 
1250 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn reject: %p\n", pep_priv);
1251 
1252 	return FI_SUCCESS;
1253 }
1254 
gnix_pep_open(struct fid_fabric * fabric,struct fi_info * info,struct fid_pep ** pep,void * context)1255 DIRECT_FN int gnix_pep_open(struct fid_fabric *fabric,
1256 			    struct fi_info *info, struct fid_pep **pep,
1257 			    void *context)
1258 {
1259 	struct gnix_fid_fabric *fabric_priv;
1260 	struct gnix_fid_pep *pep_priv;
1261 	struct gnix_ep_name *ep_name;
1262 
1263 	if (!fabric || !info || !pep)
1264 		return -FI_EINVAL;
1265 
1266 	fabric_priv = container_of(fabric, struct gnix_fid_fabric, fab_fid);
1267 
1268 	pep_priv = calloc(1, sizeof(*pep_priv));
1269 	if (!pep_priv)
1270 		return -FI_ENOMEM;
1271 
1272 	pep_priv->pep_fid.fid.fclass = FI_CLASS_PEP;
1273 	pep_priv->pep_fid.fid.context = context;
1274 
1275 	pep_priv->pep_fid.fid.ops = &gnix_pep_fi_ops;
1276 	pep_priv->pep_fid.ops = &gnix_pep_ops_ep;
1277 	pep_priv->pep_fid.cm = &gnix_pep_ops_cm;
1278 	pep_priv->fabric = fabric_priv;
1279 	pep_priv->info = fi_dupinfo(info);
1280 	pep_priv->info->addr_format = info->addr_format;
1281 
1282 	pep_priv->listen_fd = -1;
1283 	pep_priv->backlog = 5; /* TODO set via fi_control parameter. */
1284 	fastlock_init(&pep_priv->lock);
1285 
1286 	if (info->src_addr) {
1287 		ep_name = info->src_addr;
1288 		info->src_addrlen = sizeof(struct sockaddr_in);
1289 
1290 		pep_priv->bound = 1;
1291 		memcpy(&pep_priv->src_addr, ep_name, info->src_addrlen);
1292 	} else {
1293 		pep_priv->bound = 0;
1294 	}
1295 
1296 	_gnix_ref_init(&pep_priv->ref_cnt, 1, __pep_destruct);
1297 
1298 	*pep = &pep_priv->pep_fid;
1299 
1300 	GNIX_DEBUG(FI_LOG_EP_CTRL, "Opened PEP: %p\n", pep_priv);
1301 
1302 	return FI_SUCCESS;
1303 }
1304 
1305 struct fi_ops gnix_pep_fi_ops = {
1306 	.size = sizeof(struct fi_ops),
1307 	.close = gnix_pep_close,
1308 	.bind = gnix_pep_bind,
1309 	.control = fi_no_control,
1310 	.ops_open = fi_no_ops_open,
1311 };
1312 
1313 struct fi_ops_ep gnix_pep_ops_ep = {
1314 	.size = sizeof(struct fi_ops_ep),
1315 	.cancel = fi_no_cancel,
1316 	.getopt = gnix_pep_getopt,
1317 	.setopt = fi_no_setopt,
1318 	.tx_ctx = fi_no_tx_ctx,
1319 	.rx_ctx = fi_no_rx_ctx,
1320 	.rx_size_left = fi_no_rx_size_left,
1321 	.tx_size_left = fi_no_tx_size_left,
1322 };
1323 
1324 struct fi_ops_cm gnix_pep_ops_cm = {
1325 	.size = sizeof(struct fi_ops_cm),
1326 	.setname = gnix_setname,
1327 	.getname = gnix_getname,
1328 	.getpeer = fi_no_getpeer,
1329 	.connect = fi_no_connect,
1330 	.listen = gnix_pep_listen,
1331 	.accept = fi_no_accept,
1332 	.reject = gnix_reject,
1333 	.shutdown = fi_no_shutdown,
1334 	.join = fi_no_join,
1335 };
1336 
1337