static int usdf_domain_bind(struct fid *fid, struct fid *bfid, uint64_t flags) { struct usdf_domain *udp; USDF_TRACE_SYS(DOMAIN, "\n"); if (flags & FI_REG_MR) { USDF_WARN_SYS(DOMAIN, "FI_REG_MR for EQs is not supported by the usnic provider"); return -FI_EOPNOTSUPP; } udp = dom_fidtou(fid); switch (bfid->fclass) { case FI_CLASS_EQ: if (udp->dom_eq != NULL) { return -FI_EINVAL; } udp->dom_eq = eq_fidtou(bfid); ofi_atomic_inc32(&udp->dom_eq->eq_refcnt); break; default: return -FI_EINVAL; } return 0; }
static int usdf_pep_reject(struct fid_pep *pep, fid_t handle, const void *param, size_t paramlen) { USDF_TRACE_SYS(EP_CTRL, "\n"); return -FI_ENOSYS; }
static int usdf_pep_listen(struct fid_pep *fpep) { struct usdf_pep *pep; struct epoll_event ev; struct usdf_fabric *fp; int ret; USDF_TRACE_SYS(EP_CTRL, "\n"); pep = pep_ftou(fpep); fp = pep->pep_fabric; ret = listen(pep->pep_sock, pep->pep_backlog); if (ret != 0) { return -errno; } pep->pep_pollitem.pi_rtn = usdf_pep_listen_cb; pep->pep_pollitem.pi_context = pep; ev.events = EPOLLIN; ev.data.ptr = &pep->pep_pollitem; ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_ADD, pep->pep_sock, &ev); if (ret == -1) { return -errno; } return 0; }
static ssize_t usdf_cq_readerr_soft(struct fid_cq *fcq, struct fi_cq_err_entry *entry, uint64_t flags) { struct usdf_cq *cq; struct usdf_cq_soft_entry *tail; USDF_TRACE_SYS(CQ, "\n"); cq = container_of(fcq, struct usdf_cq, cq_fid); tail = cq->c.soft.cq_tail; entry->op_context = tail->cse_context; entry->flags = 0; entry->prov_errno = tail->cse_prov_errno; entry->err = entry->prov_errno; tail++; if (tail == cq->c.soft.cq_end) { tail = cq->c.soft.cq_comps; } cq->c.soft.cq_tail = tail; return 1; }
static int usdf_pep_bind(fid_t fid, fid_t bfid, uint64_t flags) { struct usdf_pep *pep; USDF_TRACE_SYS(EP_CTRL, "\n"); pep = pep_fidtou(fid); switch (bfid->fclass) { case FI_CLASS_EQ: if (pep->pep_eq != NULL) { return -FI_EINVAL; } pep->pep_eq = eq_fidtou(bfid); atomic_inc(&pep->pep_eq->eq_refcnt); break; default: return -FI_EINVAL; } return 0; }
static int usdf_domain_close(fid_t fid) { struct usdf_domain *udp; int ret; USDF_TRACE_SYS(DOMAIN, "\n"); udp = container_of(fid, struct usdf_domain, dom_fid.fid); if (ofi_atomic_get32(&udp->dom_refcnt) > 0) { return -FI_EBUSY; } if (udp->dom_dev != NULL) { ret = usd_close(udp->dom_dev); if (ret != 0) { return ret; } } usdf_dom_rdc_free_data(udp); if (udp->dom_eq != NULL) { ofi_atomic_dec32(&udp->dom_eq->eq_refcnt); } ofi_atomic_dec32(&udp->dom_fabric->fab_refcnt); LIST_REMOVE(udp, dom_link); fi_freeinfo(udp->dom_info); free(udp); return 0; }
/* * Return local address of an EP */ int usdf_cm_rdm_getname(fid_t fid, void *addr, size_t *addrlen) { struct usdf_ep *ep; struct usdf_rx *rx; struct sockaddr_in sin; size_t copylen; USDF_TRACE_SYS(EP_CTRL, "\n"); ep = ep_fidtou(fid); rx = ep->ep_rx; copylen = sizeof(sin); if (copylen > *addrlen) { copylen = *addrlen; } *addrlen = sizeof(sin); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ep->ep_domain->dom_fabric->fab_dev_attrs->uda_ipaddr_be; if (rx == NULL || rx->rx_qp == NULL) { sin.sin_port = 0; } else { sin.sin_port = to_qpi(rx->rx_qp)->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port; } memcpy(addr, &sin, copylen); if (copylen < sizeof(sin)) { return -FI_ETOOSMALL; } else { return 0; } }
ssize_t usdf_dgram_senddata(struct fid_ep *fep, const void *buf, size_t len, void *desc, uint64_t data, fi_addr_t dest_addr, void *context) { USDF_TRACE_SYS(EP_DATA, "\n"); /* XXX delete once implemented */ return -FI_ENOSYS; }
static int usdf_pep_listen(struct fid_pep *fpep) { struct usdf_pep *pep; struct epoll_event ev; struct usdf_fabric *fp; int ret; USDF_TRACE_SYS(EP_CTRL, "\n"); pep = pep_ftou(fpep); fp = pep->pep_fabric; switch (pep->pep_state) { case USDF_PEP_UNBOUND: case USDF_PEP_BOUND: break; case USDF_PEP_LISTENING: USDF_WARN_SYS(EP_CTRL, "PEP already LISTENING!\n"); return -FI_EOPBADSTATE; case USDF_PEP_ROBBED: USDF_WARN_SYS(EP_CTRL, "PEP already consumed, you may only fi_close() now\n"); return -FI_EOPBADSTATE; default: USDF_WARN_SYS(EP_CTRL, "unhandled case!\n"); abort(); } /* we could already be bound if the user called fi_setname() or if we * already did the bind in a previous call to usdf_pep_listen() and the * listen(2) call failed */ if (pep->pep_state == USDF_PEP_UNBOUND) { ret = bind(pep->pep_sock, (struct sockaddr *)&pep->pep_src_addr, sizeof(struct sockaddr_in)); if (ret == -1) { return -errno; } pep->pep_state = USDF_PEP_BOUND; } ret = listen(pep->pep_sock, pep->pep_backlog); if (ret != 0) { return -errno; } pep->pep_state = USDF_PEP_LISTENING; pep->pep_pollitem.pi_rtn = usdf_pep_listen_cb; pep->pep_pollitem.pi_context = pep; ev.events = EPOLLIN; ev.data.ptr = &pep->pep_pollitem; ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_ADD, pep->pep_sock, &ev); if (ret == -1) { return -errno; } return 0; }
int usdf_cq_open(struct fid_domain *domain, struct fi_cq_attr *attr, struct fid_cq **cq_o, void *context) { struct usdf_cq *cq; struct usdf_domain *udp; int ret; USDF_TRACE_SYS(CQ, "\n"); udp = dom_ftou(domain); ret = usdf_cq_process_attr(attr, udp); if (ret != 0) { return ret; } cq = calloc(1, sizeof(*cq)); if (cq == NULL) { return -FI_ENOMEM; } cq->cq_domain = udp; cq->cq_fid.fid.fclass = FI_CLASS_CQ; cq->cq_fid.fid.context = context; cq->cq_fid.fid.ops = &usdf_cq_fi_ops; atomic_initialize(&cq->cq_refcnt, 0); switch (attr->format) { case FI_CQ_FORMAT_CONTEXT: cq->cq_fid.ops = &usdf_cq_context_ops; break; case FI_CQ_FORMAT_MSG: cq->cq_fid.ops = &usdf_cq_msg_ops; break; case FI_CQ_FORMAT_DATA: cq->cq_fid.ops = &usdf_cq_data_ops; break; default: ret = -FI_ENOSYS; goto fail; } cq->cq_attr = *attr; *cq_o = &cq->cq_fid; return 0; fail: if (cq != NULL) { if (cq->c.hard.cq_cq != NULL) { usd_destroy_cq(cq->c.hard.cq_cq); } free(cq); } return ret; }
int usdf_endpoint_open(struct fid_domain *domain, struct fi_info *info, struct fid_ep **ep_o, void *context) { USDF_TRACE_SYS(EP_CTRL, "\n"); switch (info->ep_attr->type) { case FI_EP_DGRAM: return usdf_ep_dgram_open(domain, info, ep_o, context); case FI_EP_MSG: return usdf_ep_msg_open(domain, info, ep_o, context); case FI_EP_RDM: return usdf_ep_rdm_open(domain, info, ep_o, context); default: return -FI_ENODEV; } }
int usdf_cm_msg_getname(fid_t fid, void *addr, size_t *addrlen) { struct usdf_ep *ep; size_t copylen; USDF_TRACE_SYS(EP_CTRL, "\n"); ep = ep_fidtou(fid); copylen = MIN(sizeof(ep->e.msg.ep_lcl_addr), *addrlen); *addrlen = sizeof(ep->e.msg.ep_lcl_addr); memcpy(addr, &ep->e.msg.ep_lcl_addr, copylen); if (copylen < sizeof(ep->e.msg.ep_lcl_addr)) return -FI_ETOOSMALL; else return 0; }
static int usdf_cq_close(fid_t fid) { struct usdf_cq *cq; struct usdf_cq_hard *hcq; int ret; USDF_TRACE_SYS(CQ, "\n"); cq = container_of(fid, struct usdf_cq, cq_fid.fid); if (atomic_get(&cq->cq_refcnt) > 0) { return -FI_EBUSY; } if (usdf_cq_is_soft(cq)) { while (!TAILQ_EMPTY(&cq->c.soft.cq_list)) { hcq = TAILQ_FIRST(&cq->c.soft.cq_list); if (atomic_get(&hcq->cqh_refcnt) > 0) { return -FI_EBUSY; } TAILQ_REMOVE(&cq->c.soft.cq_list, hcq, cqh_link); if (hcq->cqh_ucq != NULL) { ret = usd_destroy_cq(hcq->cqh_ucq); if (ret != 0) { return ret; } } free(hcq); } } else { if (cq->c.hard.cq_cq) { ret = usd_destroy_cq(cq->c.hard.cq_cq); if (ret != 0) { return ret; } } } free(cq); return 0; }
static ssize_t usdf_cq_readerr(struct fid_cq *fcq, struct fi_cq_err_entry *entry, uint64_t flags) { struct usdf_cq *cq; USDF_TRACE_SYS(CQ, "\n"); cq = container_of(fcq, struct usdf_cq, cq_fid); // The return values are analogous to sockets cq_readerr if (cq->cq_comp.uc_status == 0) { return -FI_EAGAIN; } entry->op_context = cq->cq_comp.uc_context; entry->flags = 0; switch (cq->cq_comp.uc_status) { case USD_COMPSTAT_SUCCESS: entry->prov_errno = FI_SUCCESS; break; case USD_COMPSTAT_ERROR_CRC: entry->prov_errno = FI_ECRC; break; case USD_COMPSTAT_ERROR_TRUNC: entry->prov_errno = FI_ETRUNC; break; case USD_COMPSTAT_ERROR_TIMEOUT: entry->prov_errno = FI_ETIMEDOUT; break; case USD_COMPSTAT_ERROR_INTERNAL: default: entry->prov_errno = FI_EOTHER; break; } entry->err = entry->prov_errno; cq->cq_comp.uc_status = 0; return 1; }
static int usdf_pep_getname(fid_t fid, void *addr, size_t *addrlen) { int ret; struct usdf_pep *pep; size_t copylen; USDF_TRACE_SYS(EP_CTRL, "\n"); ret = FI_SUCCESS; pep = pep_fidtou(fid); copylen = sizeof(pep->pep_src_addr); memcpy(addr, &pep->pep_src_addr, MIN(copylen, *addrlen)); if (*addrlen < copylen) { USDF_WARN_SYS(EP_CTRL, "*addrlen is too short\n"); ret = -FI_ETOOSMALL; } *addrlen = copylen; return ret; }
int usdf_cm_dgram_getname(fid_t fid, void *addr, size_t *addrlen) { int ret; struct usdf_ep *ep; struct sockaddr_in sin; socklen_t slen; size_t copylen; USDF_TRACE_SYS(EP_CTRL, "\n"); ep = ep_fidtou(fid); copylen = MIN(sizeof(sin), *addrlen); *addrlen = sizeof(sin); memset(&sin, 0, sizeof(sin)); if (ep->e.dg.ep_qp == NULL) { sin.sin_family = AF_INET; sin.sin_addr.s_addr = ep->ep_domain->dom_fabric->fab_dev_attrs->uda_ipaddr_be; sin.sin_port = 0; } else { slen = sizeof(sin); ret = getsockname(ep->e.dg.ep_sock, (struct sockaddr *)&sin, &slen); if (ret == -1) { return -errno; } assert(((struct sockaddr *)&sin)->sa_family == AF_INET); assert(slen == sizeof(sin)); assert(sin.sin_addr.s_addr == ep->ep_domain->dom_fabric->fab_dev_attrs->uda_ipaddr_be); } memcpy(addr, &sin, copylen); if (copylen < sizeof(sin)) return -FI_ETOOSMALL; else return 0; }
static int usdf_pep_close(fid_t fid) { struct usdf_pep *pep; USDF_TRACE_SYS(EP_CTRL, "\n"); pep = pep_fidtou(fid); if (atomic_get(&pep->pep_refcnt) > 0) { return -FI_EBUSY; } usdf_pep_free_cr_lists(pep); close(pep->pep_sock); if (pep->pep_eq != NULL) { atomic_dec(&pep->pep_eq->eq_refcnt); } atomic_dec(&pep->pep_fabric->fab_refcnt); free(pep); return 0; }
static int usdf_domain_bind(struct fid *fid, struct fid *bfid, uint64_t flags) { struct usdf_domain *udp; USDF_TRACE_SYS(DOMAIN, "\n"); udp = dom_fidtou(fid); switch (bfid->fclass) { case FI_CLASS_EQ: if (udp->dom_eq != NULL) { return -FI_EINVAL; } udp->dom_eq = eq_fidtou(bfid); atomic_inc(&udp->dom_eq->eq_refcnt); break; default: return -FI_EINVAL; } return 0; }
int usdf_cm_msg_shutdown(struct fid_ep *ep, uint64_t flags) { USDF_TRACE_SYS(EP_CTRL, "\n"); return -FI_ENOSYS; }
int usdf_cm_msg_connect(struct fid_ep *fep, const void *addr, const void *param, size_t paramlen) { struct usdf_connreq *crp; struct usdf_ep *ep; struct usdf_rx *rx; struct usdf_domain *udp; const struct sockaddr_in *sin; struct epoll_event ev; struct usdf_fabric *fp; struct usdf_connreq_msg *reqp; struct usd_qp_impl *qp; int ret; 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; sin = addr; crp = NULL; crp = calloc(1, sizeof(*crp) + sizeof(struct usdf_connreq_msg) + paramlen); if (crp == NULL) { ret = -errno; goto fail; } crp->handle.fclass = FI_CLASS_CONNREQ; crp->cr_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (crp->cr_sockfd == -1) { ret = -errno; goto fail; } ret = fcntl(crp->cr_sockfd, F_GETFL, 0); if (ret == -1) { ret = -errno; goto fail; } ret = fcntl(crp->cr_sockfd, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { ret = -errno; goto fail; } ret = usdf_ep_msg_get_queues(ep); if (ret != 0) { goto fail; } rx = ep->ep_rx; qp = to_qpi(rx->rx_qp); ret = connect(crp->cr_sockfd, (struct sockaddr *)sin, sizeof(*sin)); if (ret != 0 && errno != EINPROGRESS) { ret = -errno; goto fail; } /* register for notification when connect completes */ crp->cr_pollitem.pi_rtn = usdf_cm_msg_connect_cb_wr; crp->cr_pollitem.pi_context = crp; ev.events = EPOLLOUT; ev.data.ptr = &crp->cr_pollitem; ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_ADD, crp->cr_sockfd, &ev); if (ret != 0) { crp->cr_pollitem.pi_rtn = NULL; ret = -errno; goto fail; } /* allocate remote 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_ep = ep; reqp = (struct usdf_connreq_msg *)crp->cr_data; 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_datalen = htonl(paramlen); memcpy(reqp->creq_data, param, paramlen); return 0; fail: if (crp != NULL) { if (crp->cr_sockfd != -1) { close(crp->cr_sockfd); } free(crp); } usdf_ep_msg_release_queues(ep); return ret; }
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; }
int usdf_cm_msg_connect(struct fid_ep *fep, const void *addr, const void *param, size_t paramlen) { struct usdf_connreq *crp; struct usdf_ep *ep; struct usdf_rx *rx; struct usdf_domain *udp; const struct sockaddr_in *sin; struct epoll_event ev; struct usdf_fabric *fp; struct usdf_connreq_msg *reqp; struct usd_qp_impl *qp; size_t request_size; int ret; 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; sin = addr; /* Although paramlen may be less than USDF_MAX_CONN_DATA, the same crp * struct is used for receiving the accept and reject payload. The * structure has to be prepared to receive the maximum allowable amount * of data per transfer. The maximum size includes the connection * request structure, the connection request message, and the maximum * amount of data per connection request message. */ request_size = sizeof(*crp) + sizeof(*reqp) + USDF_MAX_CONN_DATA; crp = calloc(1, request_size); if (crp == NULL) { ret = -errno; goto fail; } ep->e.msg.ep_connreq = crp; crp->handle.fclass = FI_CLASS_CONNREQ; if (ep->e.msg.ep_cm_sock == -1) { crp->cr_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (crp->cr_sockfd == -1) { ret = -errno; goto fail; } } else { crp->cr_sockfd = ep->e.msg.ep_cm_sock; ep->e.msg.ep_cm_sock = -1; } ret = fi_fd_nonblock(crp->cr_sockfd); if (ret) { ret = -errno; goto fail; } ret = usdf_ep_msg_get_queues(ep); if (ret != 0) { goto fail; } rx = ep->ep_rx; qp = to_qpi(rx->rx_qp); ret = connect(crp->cr_sockfd, (struct sockaddr *)sin, sizeof(*sin)); if (ret != 0 && errno != EINPROGRESS) { ret = -errno; goto fail; } /* If cr_sockfd was previously unbound, connect(2) will do a a bind(2) * for us. Update our snapshot of the locally bound address. */ ret = usdf_msg_upd_lcl_addr(ep); if (ret) goto fail; /* allocate remote 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_ep = ep; reqp = (struct usdf_connreq_msg *)crp->cr_data; 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; reqp->creq_datalen = htonl(paramlen); memcpy(reqp->creq_data, param, paramlen); /* register for notification when connect completes */ crp->cr_pollitem.pi_rtn = usdf_cm_msg_connect_cb_wr; crp->cr_pollitem.pi_context = crp; ev.events = EPOLLOUT; ev.data.ptr = &crp->cr_pollitem; ret = epoll_ctl(fp->fab_epollfd, EPOLL_CTL_ADD, crp->cr_sockfd, &ev); if (ret != 0) { crp->cr_pollitem.pi_rtn = NULL; ret = -errno; goto fail; } return 0; fail: if (crp != NULL) { if (crp->cr_sockfd != -1) { close(crp->cr_sockfd); } free(crp); ep->e.msg.ep_connreq = NULL; } usdf_ep_msg_release_queues(ep); return ret; }
int usdf_pep_open(struct fid_fabric *fabric, struct fi_info *info, struct fid_pep **pep_o, void *context) { struct usdf_pep *pep; struct usdf_fabric *fp; struct sockaddr_in *sin; int ret; int optval; USDF_TRACE_SYS(EP_CTRL, "\n"); if (!info) { USDF_DBG_SYS(EP_CTRL, "null fi_info struct is invalid\n"); return -FI_EINVAL; } if (info->ep_attr->type != FI_EP_MSG) { return -FI_ENODEV; } if ((info->caps & ~USDF_MSG_CAPS) != 0) { return -FI_EBADF; } switch (info->addr_format) { case FI_SOCKADDR: if (((struct sockaddr *)info->src_addr)->sa_family != AF_INET) { USDF_WARN_SYS(EP_CTRL, "non-AF_INET src_addr specified\n"); return -FI_EINVAL; } break; case FI_SOCKADDR_IN: break; default: USDF_WARN_SYS(EP_CTRL, "unknown/unsupported addr_format\n"); return -FI_EINVAL; } if (info->src_addrlen && info->src_addrlen != sizeof(struct sockaddr_in)) { USDF_WARN_SYS(EP_CTRL, "unexpected src_addrlen\n"); return -FI_EINVAL; } fp = fab_ftou(fabric); pep = calloc(1, sizeof(*pep)); if (pep == NULL) { return -FI_ENOMEM; } pep->pep_fid.fid.fclass = FI_CLASS_PEP; pep->pep_fid.fid.context = context; pep->pep_fid.fid.ops = &usdf_pep_ops; pep->pep_fid.ops = &usdf_pep_base_ops; pep->pep_fid.cm = &usdf_pep_cm_ops; pep->pep_fabric = fp; pep->pep_state = USDF_PEP_UNBOUND; pep->pep_sock = socket(AF_INET, SOCK_STREAM, 0); if (pep->pep_sock == -1) { ret = -errno; goto fail; } ret = fcntl(pep->pep_sock, F_GETFL, 0); if (ret == -1) { ret = -errno; goto fail; } ret = fcntl(pep->pep_sock, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { ret = -errno; goto fail; } /* set SO_REUSEADDR to prevent annoying "Address already in use" errors * on successive runs of programs listening on a well known port */ optval = 1; ret = setsockopt(pep->pep_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (ret == -1) { ret = -errno; goto fail; } pep->pep_info = fi_dupinfo(info); if (!pep->pep_info) { ret = -FI_ENOMEM; goto fail; } if (info->src_addrlen == 0) { /* Copy the source address information from the device * attributes. */ pep->pep_info->src_addrlen = sizeof(struct sockaddr_in); sin = calloc(1, pep->pep_info->src_addrlen); if (!sin) { USDF_WARN_SYS(EP_CTRL, "calloc for src address failed\n"); goto fail; } sin->sin_family = AF_INET; sin->sin_addr.s_addr = fp->fab_dev_attrs->uda_ipaddr_be; pep->pep_info->src_addr = sin; } memcpy(&pep->pep_src_addr, pep->pep_info->src_addr, pep->pep_info->src_addrlen); /* initialize connreq freelist */ ret = pthread_spin_init(&pep->pep_cr_lock, PTHREAD_PROCESS_PRIVATE); if (ret != 0) { ret = -ret; goto fail; } TAILQ_INIT(&pep->pep_cr_free); TAILQ_INIT(&pep->pep_cr_pending); pep->pep_backlog = 10; ret = usdf_pep_grow_backlog(pep); if (ret != 0) { goto fail; } atomic_initialize(&pep->pep_refcnt, 0); atomic_inc(&fp->fab_refcnt); *pep_o = pep_utof(pep); return 0; fail: if (pep != NULL) { usdf_pep_free_cr_lists(pep); if (pep->pep_sock != -1) { close(pep->pep_sock); } fi_freeinfo(pep->pep_info); free(pep); } return ret; }
static int usdf_pep_setname(fid_t fid, void *addr, size_t addrlen) { int ret; struct usdf_pep *pep; uint32_t req_addr_be; socklen_t socklen; char namebuf[INET_ADDRSTRLEN]; char servbuf[INET_ADDRSTRLEN]; USDF_TRACE_SYS(EP_CTRL, "\n"); pep = pep_fidtou(fid); if (pep->pep_state != USDF_PEP_UNBOUND) { USDF_WARN_SYS(EP_CTRL, "PEP cannot be bound\n"); return -FI_EOPBADSTATE; } if (((struct sockaddr *)addr)->sa_family != AF_INET) { USDF_WARN_SYS(EP_CTRL, "non-AF_INET address given\n"); return -FI_EINVAL; } if (addrlen != sizeof(struct sockaddr_in)) { USDF_WARN_SYS(EP_CTRL, "unexpected src_addrlen\n"); return -FI_EINVAL; } req_addr_be = ((struct sockaddr_in *)addr)->sin_addr.s_addr; namebuf[0] = '\0'; servbuf[0] = '\0'; ret = getnameinfo((struct sockaddr*)addr, addrlen, namebuf, sizeof(namebuf), servbuf, sizeof(servbuf), NI_NUMERICHOST|NI_NUMERICSERV); if (ret != 0) USDF_WARN_SYS(EP_CTRL, "unable to getnameinfo(0x%x)\n", req_addr_be); if (req_addr_be != pep->pep_fabric->fab_dev_attrs->uda_ipaddr_be) { USDF_WARN_SYS(EP_CTRL, "requested addr (%s:%s) does not match fabric addr\n", namebuf, servbuf); return -FI_EADDRNOTAVAIL; } ret = bind(pep->pep_sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); if (ret == -1) { return -errno; } pep->pep_state = USDF_PEP_BOUND; /* store the resulting port so that can implement getname() properly */ socklen = sizeof(pep->pep_src_addr); ret = getsockname(pep->pep_sock, &pep->pep_src_addr, &socklen); if (ret == -1) { ret = -errno; USDF_WARN_SYS(EP_CTRL, "getsockname failed %d (%s), PEP may be in bad state\n", ret, strerror(-ret)); return ret; } return 0; }
static ssize_t usdf_pep_cancel(fid_t fid, void *context) { USDF_TRACE_SYS(EP_CTRL, "\n"); return -FI_EINVAL; }
int usdf_pep_open(struct fid_fabric *fabric, struct fi_info *info, struct fid_pep **pep_o, void *context) { struct usdf_pep *pep; struct usdf_fabric *fp; int ret; int optval; USDF_TRACE_SYS(EP_CTRL, "\n"); if (info->ep_attr->type != FI_EP_MSG) { return -FI_ENODEV; } if ((info->caps & ~USDF_MSG_CAPS) != 0) { return -FI_EBADF; } fp = fab_ftou(fabric); pep = calloc(1, sizeof(*pep)); if (pep == NULL) { return -FI_ENOMEM; } pep->pep_fid.fid.fclass = FI_CLASS_PEP; pep->pep_fid.fid.context = context; pep->pep_fid.fid.ops = &usdf_pep_ops; pep->pep_fid.ops = &usdf_pep_base_ops; pep->pep_fid.cm = &usdf_pep_cm_ops; pep->pep_fabric = fp; pep->pep_sock = socket(AF_INET, SOCK_STREAM, 0); if (pep->pep_sock == -1) { ret = -errno; goto fail; } ret = fcntl(pep->pep_sock, F_GETFL, 0); if (ret == -1) { ret = -errno; goto fail; } ret = fcntl(pep->pep_sock, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { ret = -errno; goto fail; } /* set SO_REUSEADDR to prevent annoying "Address already in use" errors * on successive runs of programs listening on a well known port */ optval = 1; ret = setsockopt(pep->pep_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (ret == -1) { ret = -errno; goto fail; } ret = bind(pep->pep_sock, (struct sockaddr *)info->src_addr, info->src_addrlen); if (ret == -1) { ret = -errno; goto fail; } /* initialize connreq freelist */ ret = pthread_spin_init(&pep->pep_cr_lock, PTHREAD_PROCESS_PRIVATE); if (ret != 0) { ret = -ret; goto fail; } TAILQ_INIT(&pep->pep_cr_free); TAILQ_INIT(&pep->pep_cr_pending); pep->pep_backlog = 10; ret = usdf_pep_grow_backlog(pep); if (ret != 0) { goto fail; } atomic_initialize(&pep->pep_refcnt, 0); atomic_inc(&fp->fab_refcnt); *pep_o = pep_utof(pep); return 0; fail: if (pep != NULL) { usdf_pep_free_cr_lists(pep); if (pep->pep_sock != -1) { close(pep->pep_sock); } free(pep); } return ret; }
int usdf_domain_open(struct fid_fabric *fabric, struct fi_info *info, struct fid_domain **domain, void *context) { struct usdf_fabric *fp; struct usdf_domain *udp; struct sockaddr_in *sin; size_t addrlen; int ret; #if ENABLE_DEBUG char requested[INET_ADDRSTRLEN], actual[INET_ADDRSTRLEN]; #endif USDF_TRACE_SYS(DOMAIN, "\n"); sin = NULL; fp = fab_fidtou(fabric); if (info->domain_attr != NULL) { /* No versioning information available here. */ if (!usdf_domain_checkname(0, fp->fab_dev_attrs, info->domain_attr->name)) { USDF_WARN_SYS(DOMAIN, "domain name mismatch\n"); return -FI_ENODATA; } if (ofi_check_mr_mode(fabric->api_version, OFI_MR_BASIC_MAP | FI_MR_LOCAL, info->domain_attr->mr_mode)) { /* the caller ignored our fi_getinfo results */ USDF_WARN_SYS(DOMAIN, "MR mode (%d) not supported\n", info->domain_attr->mr_mode); return -FI_ENODATA; } } udp = calloc(1, sizeof *udp); if (udp == NULL) { USDF_DBG("unable to alloc mem for domain\n"); ret = -FI_ENOMEM; goto fail; } USDF_DBG("uda_devname=%s\n", fp->fab_dev_attrs->uda_devname); /* * Make sure address format is good and matches this fabric */ switch (info->addr_format) { case FI_SOCKADDR: addrlen = sizeof(struct sockaddr); sin = info->src_addr; break; case FI_SOCKADDR_IN: addrlen = sizeof(struct sockaddr_in); sin = info->src_addr; break; case FI_ADDR_STR: sin = usdf_format_to_sin(info, info->src_addr); goto skip_size_check; default: ret = -FI_EINVAL; goto fail; } if (info->src_addrlen != addrlen) { ret = -FI_EINVAL; goto fail; } skip_size_check: if (sin->sin_family != AF_INET || sin->sin_addr.s_addr != fp->fab_dev_attrs->uda_ipaddr_be) { USDF_DBG_SYS(DOMAIN, "requested src_addr (%s) != fabric addr (%s)\n", inet_ntop(AF_INET, &sin->sin_addr.s_addr, requested, sizeof(requested)), inet_ntop(AF_INET, &fp->fab_dev_attrs->uda_ipaddr_be, actual, sizeof(actual))); ret = -FI_EINVAL; usdf_free_sin_if_needed(info, sin); goto fail; } usdf_free_sin_if_needed(info, sin); ret = usd_open(fp->fab_dev_attrs->uda_devname, &udp->dom_dev); if (ret != 0) { goto fail; } udp->dom_fid.fid.fclass = FI_CLASS_DOMAIN; udp->dom_fid.fid.context = context; udp->dom_fid.fid.ops = &usdf_fid_ops; udp->dom_fid.ops = &usdf_domain_ops; udp->dom_fid.mr = &usdf_domain_mr_ops; ret = pthread_spin_init(&udp->dom_progress_lock, PTHREAD_PROCESS_PRIVATE); if (ret != 0) { ret = -ret; goto fail; } TAILQ_INIT(&udp->dom_tx_ready); TAILQ_INIT(&udp->dom_hcq_list); udp->dom_info = fi_dupinfo(info); if (udp->dom_info == NULL) { ret = -FI_ENOMEM; goto fail; } if (udp->dom_info->dest_addr != NULL) { free(udp->dom_info->dest_addr); udp->dom_info->dest_addr = NULL; } ret = usdf_dom_rdc_alloc_data(udp); if (ret != 0) { goto fail; } udp->dom_fabric = fp; LIST_INSERT_HEAD(&fp->fab_domain_list, udp, dom_link); ofi_atomic_initialize32(&udp->dom_refcnt, 0); ofi_atomic_inc32(&fp->fab_refcnt); *domain = &udp->dom_fid; return 0; fail: if (udp != NULL) { if (udp->dom_info != NULL) { fi_freeinfo(udp->dom_info); } if (udp->dom_dev != NULL) { usd_close(udp->dom_dev); } usdf_dom_rdc_free_data(udp); free(udp); } return ret; }