/* * Connection request attempt failed */ void usdf_cm_msg_connreq_failed(struct usdf_connreq *crp, int error) { struct usdf_pep *pep; struct usdf_ep *ep; struct usdf_eq *eq; fid_t fid; struct fi_eq_err_entry err; pep = crp->cr_pep; ep = crp->cr_ep; if (ep != NULL) { fid = ep_utofid(ep); eq = ep->ep_eq; ep->ep_domain->dom_peer_tab[ep->e.msg.ep_rem_peer_id] = NULL; } else { fid = pep_utofid(pep); eq = pep->pep_eq; } err.fid = fid; err.context = NULL; err.data = 0; err.err = -error; err.prov_errno = 0; err.err_data = NULL; err.err_data_size = 0; usdf_eq_write_internal(eq, 0, &err, sizeof(err), USDF_EVENT_FLAG_ERROR); usdf_cm_msg_connreq_cleanup(crp); }
/* Register as a callback triggered by the socket becoming writeable. Write as * much data as can be written in a single write, and keep track of how much * data is left. If the data is not fully written, it will finish getting * written in another iteration of the progression. */ static int usdf_pep_reject_async(void *vreq) { struct usdf_connreq *crp; int ret; crp = vreq; do { ret = write(crp->cr_sockfd, crp->cr_ptr, crp->cr_resid); } while ((ret < 0) && (errno == EINTR)); if ((ret <= 0) && (errno != EAGAIN)) { USDF_DBG_SYS(EP_CTRL, "write failed: %s\n", strerror(errno)); usdf_cm_msg_connreq_failed(crp, -errno); return -errno; } crp->cr_resid -= ret; crp->cr_ptr += ret; if (crp->cr_resid == 0) usdf_cm_msg_connreq_cleanup(crp); return FI_SUCCESS; }
/* Report a connection management related failure. Sometimes there is connection * event data that should be copied into the generated event. If the copy_data * parameter evaluates to true, then the data will be copied. * * If data is to be generated for the error entry, then the connection request * is assumed to have the data size in host order. If something fails during * processing of the error data, then the EQ entry will still be generated * without the error data. */ void usdf_cm_report_failure(struct usdf_connreq *crp, int error, bool copy_data) { struct fi_eq_err_entry err = {0}; struct usdf_pep *pep; struct usdf_ep *ep; struct usdf_eq *eq; fid_t fid; int ret; USDF_DBG_SYS(EP_CTRL, "error=%d (%s)\n", error, fi_strerror(error)); pep = crp->cr_pep; ep = crp->cr_ep; if (ep != NULL) { fid = ep_utofid(ep); eq = ep->ep_eq; ep->ep_domain->dom_peer_tab[ep->e.msg.ep_rem_peer_id] = NULL; } else { fid = pep_utofid(pep); eq = pep->pep_eq; } /* Try to generate the space necessary for the error data. If the * function returns a number greater than or equal to 0, then it was a * success. The return value is the size of the data. */ if (copy_data) { ret = usdf_cm_generate_err_data(eq, crp, &err.err_data); if (ret >= 0) err.err_data_size = ret; } err.fid = fid; err.err = -error; usdf_eq_write_internal(eq, 0, &err, sizeof(err), USDF_EVENT_FLAG_ERROR); usdf_cm_msg_connreq_cleanup(crp); }
static int usdf_cm_msg_accept_complete(struct usdf_connreq *crp) { struct usdf_ep *ep; struct fi_eq_cm_entry entry; int ret; ep = crp->cr_ep; /* post EQ entry */ entry.fid = ep_utofid(ep); entry.info = NULL; ret = usdf_eq_write_internal(ep->ep_eq, FI_CONNECTED, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { usdf_cm_msg_connreq_failed(crp, ret); return 0; } usdf_cm_msg_connreq_cleanup(crp); return 0; }
/* * read connection request response from the listener */ static int usdf_cm_msg_connect_cb_rd(void *v) { struct usdf_connreq *crp; struct usdf_ep *ep; struct usdf_fabric *fp; struct usdf_domain *udp; struct usdf_connreq_msg *reqp; struct fi_eq_cm_entry *entry; size_t entry_len; int ret; crp = v; ep = crp->cr_ep; fp = ep->ep_domain->dom_fabric; ret = read(crp->cr_sockfd, crp->cr_ptr, crp->cr_resid); if (ret == -1) { usdf_cm_msg_connreq_failed(crp, -errno); return 0; } crp->cr_resid -= ret; reqp = (struct usdf_connreq_msg *)crp->cr_data; if (crp->cr_resid == 0 && crp->cr_ptr == crp->cr_data + sizeof(*reqp)) { reqp->creq_datalen = ntohl(reqp->creq_datalen); crp->cr_resid = reqp->creq_datalen; } /* if resid is 0 now, completely done */ if (crp->cr_resid == 0) { ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_DEL, crp->cr_sockfd, NULL); close(crp->cr_sockfd); crp->cr_sockfd = -1; entry_len = sizeof(*entry) + reqp->creq_datalen; entry = malloc(entry_len); if (entry == NULL) { usdf_cm_msg_connreq_failed(crp, -errno); return 0; } udp = ep->ep_domain; ep->e.msg.ep_lcl_peer_id = ntohs(reqp->creq_peer_id); ret = usd_create_dest_with_mac(udp->dom_dev, reqp->creq_ipaddr, reqp->creq_port, reqp->creq_mac, &ep->e.msg.ep_dest); if (ret != 0) { free(entry); usdf_cm_msg_connreq_failed(crp, ret); return 0; } entry->fid = ep_utofid(ep); entry->info = NULL; memcpy(entry->data, reqp->creq_data, reqp->creq_datalen); ret = usdf_eq_write_internal(ep->ep_eq, FI_CONNECTED, entry, entry_len, 0); free(entry); if (ret != entry_len) { free(ep->e.msg.ep_dest); ep->e.msg.ep_dest = NULL; usdf_cm_msg_connreq_failed(crp, ret); return 0; } usdf_cm_msg_connreq_cleanup(crp); } return 0; }
int usdf_cm_msg_accept(struct fid_ep *fep, const void *param, size_t paramlen) { struct usdf_ep *ep; struct usdf_rx *rx; struct usdf_domain *udp; struct usdf_fabric *fp; struct usdf_connreq *crp; struct usdf_connreq_msg *reqp; struct usd_qp_impl *qp; int ret; int n; USDF_TRACE_SYS(EP_CTRL, "\n"); if (paramlen > USDF_MAX_CONN_DATA) return -FI_EINVAL; ep = ep_ftou(fep); udp = ep->ep_domain; fp = udp->dom_fabric; crp = ep->e.msg.ep_connreq; if (crp == NULL) { return -FI_ENOTCONN; } if (ep->ep_eq == NULL) { return -FI_ENOEQ; } crp->cr_ep = ep; reqp = (struct usdf_connreq_msg *)crp->cr_data; ep->e.msg.ep_lcl_peer_id = ntohs(reqp->creq_peer_id); /* start creating the dest early */ ret = usd_create_dest_with_mac(udp->dom_dev, reqp->creq_ipaddr, reqp->creq_port, reqp->creq_mac, &ep->e.msg.ep_dest); if (ret != 0) { goto fail; } ret = usdf_ep_msg_get_queues(ep); if (ret != 0) { goto fail; } rx = ep->ep_rx; qp = to_qpi(rx->rx_qp); /* allocate a peer ID */ ep->e.msg.ep_rem_peer_id = udp->dom_next_peer; udp->dom_peer_tab[udp->dom_next_peer] = ep; ++udp->dom_next_peer; crp->cr_ptr = crp->cr_data; crp->cr_resid = sizeof(*reqp) + paramlen; reqp->creq_peer_id = htons(ep->e.msg.ep_rem_peer_id); reqp->creq_ipaddr = fp->fab_dev_attrs->uda_ipaddr_be; reqp->creq_port = qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port; memcpy(reqp->creq_mac, fp->fab_dev_attrs->uda_mac_addr, ETH_ALEN); reqp->creq_result = htonl(0); reqp->creq_datalen = htonl(paramlen); memcpy(reqp->creq_data, param, paramlen); n = write(crp->cr_sockfd, crp->cr_ptr, crp->cr_resid); if (n == -1) { usdf_cm_msg_connreq_cleanup(crp); ret = -errno; goto fail; } crp->cr_resid -= n; if (crp->cr_resid == 0) { usdf_cm_msg_accept_complete(crp); } else { // XXX set up epoll junk to send rest } return 0; fail: free(ep->e.msg.ep_dest); /* XXX release queues */ return ret; }
/* * read connection request response from the listener */ static int usdf_cm_msg_connect_cb_rd(void *v) { struct usdf_connreq *crp; struct usdf_ep *ep; struct usdf_fabric *fp; struct usdf_domain *udp; struct usdf_connreq_msg *reqp; struct fi_eq_cm_entry *entry; size_t entry_len; int ret; crp = v; ep = crp->cr_ep; fp = ep->ep_domain->dom_fabric; ret = read(crp->cr_sockfd, crp->cr_ptr, crp->cr_resid); if (ret == -1) goto report_failure_skip_data; crp->cr_ptr += ret; crp->cr_resid -= ret; reqp = (struct usdf_connreq_msg *)crp->cr_data; if (crp->cr_resid == 0 && crp->cr_ptr == crp->cr_data + sizeof(*reqp)) { reqp->creq_datalen = ntohl(reqp->creq_datalen); crp->cr_resid = reqp->creq_datalen; } /* if resid is 0 now, completely done */ if (crp->cr_resid == 0) { reqp->creq_result = ntohl(reqp->creq_result); ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_DEL, crp->cr_sockfd, NULL); close(crp->cr_sockfd); crp->cr_sockfd = -1; if (reqp->creq_result != FI_SUCCESS) { /* Copy the data since this was an explicit rejection. */ usdf_cm_report_failure(crp, reqp->creq_result, true); return 0; } entry_len = sizeof(*entry) + reqp->creq_datalen; entry = malloc(entry_len); if (entry == NULL) goto report_failure_skip_data; udp = ep->ep_domain; ep->e.msg.ep_lcl_peer_id = ntohs(reqp->creq_peer_id); ret = usd_create_dest(udp->dom_dev, reqp->creq_ipaddr, reqp->creq_port, &ep->e.msg.ep_dest); if (ret != 0) goto free_entry_and_report_failure; ep->e.msg.ep_dest->ds_dest.ds_udp.u_hdr.uh_ip.frag_off |= htons(IP_DF); entry->fid = ep_utofid(ep); entry->info = NULL; memcpy(entry->data, reqp->creq_data, reqp->creq_datalen); ret = usdf_eq_write_internal(ep->ep_eq, FI_CONNECTED, entry, entry_len, 0); if (ret != (int)entry_len) { free(ep->e.msg.ep_dest); ep->e.msg.ep_dest = NULL; goto free_entry_and_report_failure; } free(entry); usdf_cm_msg_connreq_cleanup(crp); } return 0; free_entry_and_report_failure: free(entry); report_failure_skip_data: usdf_cm_report_failure(crp, ret, false); return 0; }