DIRECT_FN STATIC int gnix_accept(struct fid_ep *ep, const void *param, size_t paramlen) { int ret; struct gnix_vc *vc; struct gnix_fid_ep *ep_priv; struct gnix_pep_sock_conn *conn; struct gnix_pep_sock_connresp resp; struct fi_eq_cm_entry eq_entry, *eqe_ptr; struct gnix_mbox *mbox = NULL; struct gnix_av_addr_entry av_entry; if (!ep || (paramlen && !param) || paramlen > GNIX_CM_DATA_MAX_SIZE) return -FI_EINVAL; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid); COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock); /* Look up and unpack the connection request used to create this EP. */ conn = (struct gnix_pep_sock_conn *)ep_priv->info->handle; if (!conn || conn->fid.fclass != FI_CLASS_CONNREQ) { ret = -FI_EINVAL; goto err_unlock; } /* Create new VC without CM data. */ av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr; av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id; ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create VC: %d\n", ret); goto err_unlock; } ep_priv->vc = vc; ep_priv->vc->peer_caps = conn->req.peer_caps; ep_priv->vc->peer_id = conn->req.vc_id; ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n", fi_strerror(-ret)); goto err_mbox_alloc; } vc->smsg_mbox = mbox; /* Initialize the GNI connection. */ ret = _gnix_vc_smsg_init(vc, conn->req.vc_id, &conn->req.vc_mbox_attr, &conn->req.cq_irq_mdh); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto err_smsg_init; } vc->conn_state = GNIX_VC_CONNECTED; /* Send ACK with VC attrs to allow peer to initialize GNI connection. */ resp.cmd = GNIX_PEP_SOCK_RESP_ACCEPT; resp.vc_id = vc->vc_id; resp.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; resp.vc_mbox_attr.msg_buffer = mbox->base; resp.vc_mbox_attr.buff_size = vc->ep->nic->mem_per_mbox; resp.vc_mbox_attr.mem_hndl = *mbox->memory_handle; resp.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset; resp.vc_mbox_attr.mbox_maxcredit = ep_priv->domain->params.mbox_maxcredit; resp.vc_mbox_attr.msg_maxsize = ep_priv->domain->params.mbox_msg_maxsize; resp.cq_irq_mdh = ep_priv->nic->irq_mem_hndl; resp.peer_caps = ep_priv->caps; resp.cm_data_len = paramlen; if (paramlen) { eqe_ptr = (struct fi_eq_cm_entry *)resp.eqe_buf; memcpy(eqe_ptr->data, param, paramlen); } ret = write(conn->sock_fd, &resp, sizeof(resp)); if (ret != sizeof(resp)) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to send resp, errno: %d\n", errno); ret = -FI_EIO; goto err_write; } /* Notify user that this side is connected. */ eq_entry.fid = &ep_priv->ep_fid.fid; ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_CONNECTED, &eq_entry, sizeof(eq_entry), 0); if (ret != sizeof(eq_entry)) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); goto err_eq_write; } /* Free the connection request. */ free(conn); ep_priv->conn_state = GNIX_EP_CONNECTED; COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn accept: %p\n", ep_priv); return FI_SUCCESS; err_eq_write: err_write: err_smsg_init: _gnix_mbox_free(ep_priv->vc->smsg_mbox); ep_priv->vc->smsg_mbox = NULL; err_mbox_alloc: _gnix_vc_destroy(ep_priv->vc); ep_priv->vc = NULL; err_unlock: COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); return ret; }
DIRECT_FN STATIC int gnix_connect(struct fid_ep *ep, const void *addr, const void *param, size_t paramlen) { int ret; struct gnix_fid_ep *ep_priv; struct sockaddr_in saddr; struct gnix_pep_sock_connreq req; struct fi_eq_cm_entry *eqe_ptr; struct gnix_vc *vc; struct gnix_mbox *mbox = NULL; struct gnix_av_addr_entry av_entry; if (!ep || !addr || (paramlen && !param) || paramlen > GNIX_CM_DATA_MAX_SIZE) return -FI_EINVAL; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid); COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock); if (ep_priv->conn_state != GNIX_EP_UNCONNECTED) { ret = -FI_EINVAL; goto err_unlock; } ret = _gnix_pe_to_ip(addr, &saddr); if (ret != FI_SUCCESS) { GNIX_INFO(FI_LOG_EP_CTRL, "Failed to translate gnix_ep_name to IP\n"); goto err_unlock; } /* Create new VC without CM data. */ av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr; av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id; ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create VC:: %d\n", ret); goto err_unlock; } ep_priv->vc = vc; ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n", fi_strerror(-ret)); goto err_mbox_alloc; } vc->smsg_mbox = mbox; ep_priv->conn_fd = socket(AF_INET, SOCK_STREAM, 0); if (ep_priv->conn_fd < 0) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create connect socket, errno: %d\n", errno); ret = -FI_ENOSPC; goto err_socket; } /* Currently blocks until connected. */ ret = connect(ep_priv->conn_fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to connect, errno: %d\n", errno); ret = -FI_EIO; goto err_connect; } req.info = *ep_priv->info; /* Note addrs are swapped. */ memcpy(&req.dest_addr, (void *)&ep_priv->src_addr, sizeof(req.dest_addr)); memcpy(&ep_priv->dest_addr, addr, sizeof(ep_priv->dest_addr)); memcpy(&req.src_addr, addr, sizeof(req.src_addr)); if (ep_priv->info->tx_attr) req.tx_attr = *ep_priv->info->tx_attr; if (ep_priv->info->rx_attr) req.rx_attr = *ep_priv->info->rx_attr; if (ep_priv->info->ep_attr) req.ep_attr = *ep_priv->info->ep_attr; if (ep_priv->info->domain_attr) req.domain_attr = *ep_priv->info->domain_attr; if (ep_priv->info->fabric_attr) req.fabric_attr = *ep_priv->info->fabric_attr; req.fabric_attr.fabric = NULL; req.domain_attr.domain = NULL; req.vc_id = vc->vc_id; req.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; req.vc_mbox_attr.msg_buffer = mbox->base; req.vc_mbox_attr.buff_size = vc->ep->nic->mem_per_mbox; req.vc_mbox_attr.mem_hndl = *mbox->memory_handle; req.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset; req.vc_mbox_attr.mbox_maxcredit = ep_priv->domain->params.mbox_maxcredit; req.vc_mbox_attr.msg_maxsize = ep_priv->domain->params.mbox_msg_maxsize; req.cq_irq_mdh = ep_priv->nic->irq_mem_hndl; req.peer_caps = ep_priv->caps; req.cm_data_len = paramlen; if (paramlen) { eqe_ptr = (struct fi_eq_cm_entry *)req.eqe_buf; memcpy(eqe_ptr->data, param, paramlen); } ret = write(ep_priv->conn_fd, &req, sizeof(req)); if (ret != sizeof(req)) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to send req, errno: %d\n", errno); ret = -FI_EIO; goto err_write; } /* set fd to non-blocking now since we can't block within the eq * progress system */ fi_fd_nonblock(ep_priv->conn_fd); ep_priv->conn_state = GNIX_EP_CONNECTING; COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn req: %p, %s\n", ep_priv, inet_ntoa(saddr.sin_addr)); return FI_SUCCESS; err_write: err_connect: close(ep_priv->conn_fd); ep_priv->conn_fd = -1; err_socket: _gnix_mbox_free(ep_priv->vc->smsg_mbox); ep_priv->vc->smsg_mbox = NULL; err_mbox_alloc: _gnix_vc_destroy(ep_priv->vc); ep_priv->vc = NULL; err_unlock: COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); return ret; }
static int __gnix_vc_conn_ack_prog_fn(void *data, int *complete_ptr) { int ret = FI_SUCCESS; int complete = 0; struct wq_hndl_conn_req *work_req_data; struct gnix_vc *vc; struct gnix_mbox *mbox = NULL; gni_smsg_attr_t smsg_mbox_attr; struct gnix_fid_ep *ep = NULL; struct gnix_fid_domain *dom = NULL; struct gnix_cm_nic *cm_nic = NULL; char sbuf[GNIX_CM_NIC_MAX_MSG_SIZE] = {0}; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); work_req_data = (struct wq_hndl_conn_req *)data; vc = work_req_data->vc; if (vc == NULL) return -FI_EINVAL; ep = vc->ep; if (ep == NULL) return -FI_EINVAL; dom = ep->domain; if (dom == NULL) return -FI_EINVAL; cm_nic = ep->cm_nic; if (cm_nic == NULL) return -FI_EINVAL; fastlock_acquire(&ep->vc_ht_lock); /* * we may have already been moved to connecting or * connected, if so early exit. */ if(vc->conn_state == GNIX_VC_CONNECTED) { complete = 1; goto exit; } /* * first see if we still need a mailbox */ if (vc->smsg_mbox == NULL) { ret = _gnix_mbox_alloc(ep->nic->mbox_hndl, &mbox); if (ret == FI_SUCCESS) vc->smsg_mbox = mbox; else goto exit; } mbox = vc->smsg_mbox; /* * prep the smsg_mbox_attr ¬ */ smsg_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; smsg_mbox_attr.msg_buffer = mbox->base; smsg_mbox_attr.buff_size = ep->nic->mem_per_mbox; smsg_mbox_attr.mem_hndl = *mbox->memory_handle; smsg_mbox_attr.mbox_offset = (uint64_t)mbox->offset; smsg_mbox_attr.mbox_maxcredit = dom->params.mbox_maxcredit; smsg_mbox_attr.msg_maxsize = dom->params.mbox_msg_maxsize; /* * serialize the resp message in the buffer */ __gnix_vc_pack_conn_resp(sbuf, work_req_data->src_vc_ptr, (uint64_t)vc, vc->vc_id, &smsg_mbox_attr); /* * try to send the message, if it succeeds, * initialize mailbox and move vc to connected * state. */ ret = _gnix_cm_nic_send(cm_nic, sbuf, GNIX_CM_NIC_MAX_MSG_SIZE, vc->peer_cm_nic_addr); if (ret == FI_SUCCESS) { ret = __gnix_vc_smsg_init(vc, work_req_data->src_vc_id, &work_req_data->src_smsg_attr); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto exit; } complete = 1; vc->conn_state = GNIX_VC_CONNECTED; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p to connected\n",vc); } else if (ret == -FI_EAGAIN) { ret = _gnix_vc_schedule(vc); ret = FI_SUCCESS; } else assert(0); exit: fastlock_release(&ep->vc_ht_lock); *complete_ptr = complete; return ret; }
static int __gnix_vc_conn_req_prog_fn(void *data, int *complete_ptr) { int ret = FI_SUCCESS; int complete = 0; struct gnix_vc *vc = (struct gnix_vc *)data; struct gnix_mbox *mbox = NULL; gni_smsg_attr_t smsg_mbox_attr; struct gnix_fid_ep *ep = NULL; struct gnix_fid_domain *dom = NULL; struct gnix_cm_nic *cm_nic = NULL; char sbuf[GNIX_CM_NIC_MAX_MSG_SIZE] = {0}; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); ep = vc->ep; if (ep == NULL) return -FI_EINVAL; dom = ep->domain; if (dom == NULL) return -FI_EINVAL; cm_nic = ep->cm_nic; if (cm_nic == NULL) return -FI_EINVAL; fastlock_acquire(&ep->vc_ht_lock); if ((vc->conn_state == GNIX_VC_CONNECTING) || (vc->conn_state == GNIX_VC_CONNECTED)) { complete = 1; goto err; } /* * sanity check that the vc is in the hash table */ if (!(vc->modes & GNIX_VC_MODE_IN_HT)) { ret = -FI_EINVAL; goto err; } /* * first see if we still need a mailbox */ if (vc->smsg_mbox == NULL) { ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox); if (ret == FI_SUCCESS) vc->smsg_mbox = mbox; else goto err; } mbox = vc->smsg_mbox; /* * prep the smsg_mbox_attr ¬ */ smsg_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; smsg_mbox_attr.msg_buffer = mbox->base; smsg_mbox_attr.buff_size = vc->ep->nic->mem_per_mbox; smsg_mbox_attr.mem_hndl = *mbox->memory_handle; smsg_mbox_attr.mbox_offset = (uint64_t)mbox->offset; smsg_mbox_attr.mbox_maxcredit = dom->params.mbox_maxcredit; smsg_mbox_attr.msg_maxsize = dom->params.mbox_msg_maxsize; /* * serialize the message in the buffer */ GNIX_DEBUG(FI_LOG_EP_CTRL, "conn req tx: (From Aries addr 0x%x Id %d to Aries 0x%x Id %d CM NIC Id %d vc %p)\n", ep->my_name.gnix_addr.device_addr, ep->my_name.gnix_addr.cdm_id, vc->peer_addr.device_addr, vc->peer_addr.cdm_id, vc->peer_cm_nic_addr.cdm_id, vc); __gnix_vc_pack_conn_req(sbuf, &vc->peer_addr, &ep->my_name.gnix_addr, vc->vc_id, (uint64_t)vc, &smsg_mbox_attr); /* * try to send the message, if -FI_EAGAIN is returned, okay, * just don't mark complete. */ ret = _gnix_cm_nic_send(cm_nic, sbuf, GNIX_CM_NIC_MAX_MSG_SIZE, vc->peer_cm_nic_addr); if (ret == FI_SUCCESS) { complete = 1; vc->conn_state = GNIX_VC_CONNECTING; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connecting\n", vc); } else if (ret == -FI_EAGAIN) { ret = FI_SUCCESS; } ret = _gnix_vc_schedule(vc); err: fastlock_release(&ep->vc_ht_lock); *complete_ptr = complete; return ret; }
/* * connect to self, since we use a lock here * the only case we need to deal with is one * vc connect request with the peer vc not yet * being set up */ static int __gnix_vc_connect_to_same_cm_nic(struct gnix_vc *vc) { int ret = FI_SUCCESS; struct gnix_fid_domain *dom = NULL; struct gnix_fid_ep *ep = NULL; struct gnix_fid_ep *ep_peer = NULL; struct gnix_cm_nic *cm_nic = NULL; struct gnix_mbox *mbox = NULL, *mbox_peer = NULL; struct gnix_vc *vc_peer; gni_smsg_attr_t smsg_mbox_attr; gni_smsg_attr_t smsg_mbox_attr_peer; gnix_ht_key_t *key_ptr; struct gnix_av_addr_entry entry; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); ep = vc->ep; if (ep == NULL) return -FI_EINVAL; cm_nic = ep->cm_nic; if (cm_nic == NULL) { ret = -FI_EINVAL; goto exit; } dom = ep->domain; if (dom == NULL) { ret = -FI_EINVAL; goto exit; } fastlock_acquire(&ep->vc_ht_lock); if ((vc->conn_state == GNIX_VC_CONNECTING) || (vc->conn_state == GNIX_VC_CONNECTED)) { fastlock_release(&ep->vc_ht_lock); return FI_SUCCESS; } else vc->conn_state = GNIX_VC_CONNECTING; fastlock_release(&ep->vc_ht_lock); GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connecting\n", vc); if (vc->smsg_mbox == NULL) { ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n", fi_strerror(-ret)); goto exit; } vc->smsg_mbox = mbox; } else mbox = vc->smsg_mbox; smsg_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; smsg_mbox_attr.msg_buffer = mbox->base; smsg_mbox_attr.buff_size = vc->ep->nic->mem_per_mbox; smsg_mbox_attr.mem_hndl = *mbox->memory_handle; smsg_mbox_attr.mbox_offset = (uint64_t)mbox->offset; smsg_mbox_attr.mbox_maxcredit = dom->params.mbox_maxcredit; smsg_mbox_attr.msg_maxsize = dom->params.mbox_msg_maxsize; key_ptr = (gnix_ht_key_t *)&vc->peer_addr; ep_peer = (struct gnix_fid_ep *)_gnix_ht_lookup(cm_nic->addr_to_ep_ht, *key_ptr); if (ep_peer == NULL) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_ht_lookup addr_to_ep failed\n"); ret = -FI_ENOENT; goto exit; } key_ptr = (gnix_ht_key_t *)&ep->my_name.gnix_addr; fastlock_acquire(&ep_peer->vc_ht_lock); vc_peer = (struct gnix_vc *)_gnix_ht_lookup(ep_peer->vc_ht, *key_ptr); /* * handle the special case of connecting to self */ if (vc_peer == vc) { ret = __gnix_vc_smsg_init(vc, vc->vc_id, &smsg_mbox_attr); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } vc->conn_state = GNIX_VC_CONNECTED; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n", vc); goto exit_w_lock; } if ((vc_peer != NULL) && (vc_peer->conn_state != GNIX_VC_CONN_NONE)) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_connect self, vc_peer in inconsistent state\n"); ret = -FI_ENOSPC; goto exit_w_lock; } if (vc_peer == NULL) { entry.gnix_addr = ep->my_name.gnix_addr; entry.cm_nic_cdm_id = ep->my_name.cm_nic_cdm_id; ret = _gnix_vc_alloc(ep_peer, &entry, &vc_peer); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_alloc returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } ret = _gnix_ht_insert(ep_peer->vc_ht, *key_ptr, vc_peer); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_ht_insert returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } vc_peer->modes |= GNIX_VC_MODE_IN_HT; } vc_peer->conn_state = GNIX_VC_CONNECTING; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connecting\n", vc_peer); if (vc_peer->smsg_mbox == NULL) { ret = _gnix_mbox_alloc(vc_peer->ep->nic->mbox_hndl, &mbox_peer); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } vc_peer->smsg_mbox = mbox_peer; } else mbox_peer = vc_peer->smsg_mbox; smsg_mbox_attr_peer.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; smsg_mbox_attr_peer.msg_buffer = mbox_peer->base; smsg_mbox_attr_peer.buff_size = vc_peer->ep->nic->mem_per_mbox; smsg_mbox_attr_peer.mem_hndl = *mbox_peer->memory_handle; smsg_mbox_attr_peer.mbox_offset = (uint64_t)mbox_peer->offset; smsg_mbox_attr_peer.mbox_maxcredit = dom->params.mbox_maxcredit; smsg_mbox_attr_peer.msg_maxsize = dom->params.mbox_msg_maxsize; ret = __gnix_vc_smsg_init(vc, vc_peer->vc_id, &smsg_mbox_attr_peer); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } ret = __gnix_vc_smsg_init(vc_peer, vc->vc_id, &smsg_mbox_attr); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto exit_w_lock; } vc->conn_state = GNIX_VC_CONNECTED; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n", vc); vc_peer->conn_state = GNIX_VC_CONNECTED; GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n", vc_peer); exit_w_lock: fastlock_release(&ep_peer->vc_ht_lock); exit: return ret; }