Test(dg_allocation, dgram_wc_post_exchg) { int ret = 0; struct gnix_cm_nic *cm_nic; struct gnix_datagram *dgram_wc, *dgram_bnd; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid); cm_nic = ep_priv->cm_nic; cr_assert((cm_nic != NULL), "cm_nic NULL"); cr_assert((cm_nic->dgram_hndl != NULL), "cm_nic dgram_hndl NULL"); ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_WC, &dgram_wc); cr_assert(!ret, "_gnix_dgram_alloc wc"); dgram_wc->callback_fn = dgram_callback_fn; ret = _gnix_dgram_wc_post(dgram_wc); cr_assert((ret == 0), "_gnix_dgram_alloc wc"); ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_BND, &dgram_bnd); cr_assert((ret == 0), "_gnix_dgram_alloc bnd"); dgram_bnd->target_addr = cm_nic->my_name.gnix_addr; local_address = cm_nic->my_name.gnix_addr; dgram_bnd->callback_fn = dgram_callback_fn; ret = _gnix_dgram_bnd_post(dgram_bnd); cr_assert(ret == 0); /* * progress auto, don't need to do anything */ while (dgram_match != 1) { ret = _gnix_cm_nic_progress(cm_nic); cr_assert(ret == 0); pthread_yield(); } ret = _gnix_dgram_free(dgram_bnd); cr_assert(!ret, "_gnix_dgram_free bnd"); ret = _gnix_dgram_free(dgram_wc); cr_assert(!ret, "_gnix_dgram_free wc"); }
Test(dg_allocation, dgram_alloc_bnd) { int ret = 0, i; struct gnix_cm_nic *cm_nic; struct gnix_datagram **dgram_ptr; struct gnix_fid_fabric *fab_priv; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid); cm_nic = ep_priv->cm_nic; cr_assert((cm_nic != NULL), "cm_nic NULL"); cr_assert((cm_nic->dgram_hndl != NULL), "cm_nic dgram_hndl NULL"); fab_priv = container_of(fab, struct gnix_fid_fabric, fab_fid); dgram_ptr = calloc(fab_priv->n_bnd_dgrams, sizeof(struct gnix_datagram *)); cr_assert((dgram_ptr != NULL), "calloc failed"); for (i = 0; i < fab_priv->n_bnd_dgrams; i++) { ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_BND, &dgram_ptr[i]); cr_assert(!ret, "_gnix_dgram_alloc bnd"); } for (i = 0; i < fab_priv->n_wc_dgrams; i++) { ret = _gnix_dgram_free(dgram_ptr[i]); cr_assert(!ret, "_gnix_dgram_free bnd"); } free(dgram_ptr); }
Test(dg_allocation, dgram_pack_unpack) { int ret = 0; ssize_t len; struct gnix_cm_nic *cm_nic; struct gnix_datagram *dgram_ptr; char in_buf[] = "0xdeadbeef"; char out_buf[GNI_DATAGRAM_MAXSIZE]; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid); cm_nic = ep_priv->cm_nic; cr_assert((cm_nic != NULL), "cm_nic NULL"); cr_assert((cm_nic->dgram_hndl != NULL), "cm_nic dgram_hndl NULL"); ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_BND, &dgram_ptr); cr_assert(!ret, "_gnix_dgram_alloc bnd"); /* * check pack/unpack for GNIX_DGRAM_IN_BUF */ len = _gnix_dgram_pack_buf(dgram_ptr, GNIX_DGRAM_IN_BUF, in_buf, sizeof(in_buf)); cr_assert(len > 0); cr_assert_eq(len, (ssize_t)sizeof(in_buf)); len = _gnix_dgram_unpack_buf(dgram_ptr, GNIX_DGRAM_IN_BUF, out_buf, sizeof(in_buf)); cr_assert(len > 0); cr_assert_eq(len, (ssize_t)sizeof(in_buf)); cr_assert_eq(0, strcmp(in_buf, out_buf)); /* * check pack/unpack for GNIX_DGRAM_OUT_BUF */ len = _gnix_dgram_pack_buf(dgram_ptr, GNIX_DGRAM_OUT_BUF, in_buf, sizeof(in_buf)); cr_assert(len > 0); cr_assert_eq(len, (ssize_t)sizeof(in_buf)); memset(out_buf, 0, sizeof(out_buf)); len = _gnix_dgram_unpack_buf(dgram_ptr, GNIX_DGRAM_OUT_BUF, out_buf, sizeof(in_buf)); cr_assert(len > 0); cr_assert_eq(len, (ssize_t)sizeof(in_buf)); cr_assert_eq(0, strcmp(in_buf, out_buf)); ret = _gnix_dgram_free(dgram_ptr); cr_assert(!ret, "_gnix_dgram_free bnd"); }
Test(dg_allocation, dgram_alloc_wc_alt) { int ret = 0, i; struct gnix_cm_nic *cm_nic; struct gnix_datagram *dgram_ptr; struct gnix_fid_fabric *fab_priv; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid); cm_nic = ep_priv->cm_nic; cr_assert((cm_nic != NULL), "cm_nic NULL"); cr_assert((cm_nic->dgram_hndl != NULL), "cm_nic dgram_hndl NULL"); fab_priv = container_of(fab, struct gnix_fid_fabric, fab_fid); for (i = 0; i < fab_priv->n_wc_dgrams; i++) { ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_WC, &dgram_ptr); cr_assert(!ret, "_gnix_dgram_alloc wc"); ret = _gnix_dgram_free(dgram_ptr); cr_assert(!ret, "_gnix_dgram_free wc"); } }
/* Destroy an unconnected VC. More Support is needed to shutdown and destroy * an active VC. */ int _gnix_vc_destroy(struct gnix_vc *vc) { int ret = FI_SUCCESS; struct gnix_nic *nic = NULL; gni_return_t status; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); if (vc->ep == NULL) { GNIX_WARN(FI_LOG_EP_CTRL, "ep null\n"); return -FI_EINVAL; } nic = vc->ep->nic; if (nic == NULL) { GNIX_WARN(FI_LOG_EP_CTRL, "ep nic null for vc %p\n", vc); return -FI_EINVAL; } /* * move vc state to terminating */ vc->conn_state = GNIX_VC_CONN_TERMINATING; /* * try to unbind the gni_ep if non-NULL. * If there are SMSG or PostFMA/RDMA outstanding * wait here for them to complete */ if (vc->gni_ep != NULL) { while (status == GNI_RC_NOT_DONE) { fastlock_acquire(&nic->lock); status = GNI_EpUnbind(vc->gni_ep); fastlock_release(&nic->lock); if ((status != GNI_RC_NOT_DONE) && (status != GNI_RC_SUCCESS)) { GNIX_WARN(FI_LOG_EP_CTRL, "GNI_EpUnBind returned %s\n", gni_err_str[status]); break; } if (status == GNI_RC_NOT_DONE) _gnix_nic_progress(nic); } fastlock_acquire(&nic->lock); status = GNI_EpDestroy(vc->gni_ep); fastlock_release(&nic->lock); if (status != GNI_RC_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "GNI_EpDestroy returned %s\n", gni_err_str[status]); } /* * if the vc is in a nic's work queue, remove it */ __gnix_vc_cancel(vc); /* * We may eventually want to check the state of the VC, if we * implement true VC shutdown. if ((vc->conn_state != GNIX_VC_CONN_NONE) && (vc->conn_state != GNIX_VC_CONN_TERMINATED)) { GNIX_WARN(FI_LOG_EP_CTRL, "vc conn state %d\n", vc->conn_state); GNIX_WARN(FI_LOG_EP_CTRL, "vc conn state error\n"); return -FI_EBUSY; } */ /* * if send_q not empty, return -FI_EBUSY * Note for FI_EP_MSG type eps, this behavior * may not be correct for handling fi_shutdown. */ if (!slist_empty(&vc->tx_queue)) { GNIX_WARN(FI_LOG_EP_CTRL, "vc sendqueue not empty\n"); return -FI_EBUSY; } fastlock_destroy(&vc->tx_queue_lock); if (vc->smsg_mbox != NULL) { ret = _gnix_mbox_free(vc->smsg_mbox); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_mbox_free returned %s\n", fi_strerror(-ret)); vc->smsg_mbox = NULL; } if (vc->dgram != NULL) { ret = _gnix_dgram_free(vc->dgram); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_free returned %s\n", fi_strerror(-ret)); vc->dgram = NULL; } ret = _gnix_nic_free_rem_id(nic, vc->vc_id); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "__gnix_vc_free_id returned %s\n", fi_strerror(-ret)); _gnix_free_bitmap(&vc->flags); free(vc); return ret; }
static int __process_datagram(struct gnix_datagram *dgram, struct gnix_address peer_address, gni_post_state_t state) { int ret = FI_SUCCESS; struct gnix_cm_nic *cm_nic = NULL; uint8_t in_tag = 0, out_tag = 0; char rcv_buf[GNIX_CM_NIC_MAX_MSG_SIZE]; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); cm_nic = (struct gnix_cm_nic *)dgram->cache; if (cm_nic == NULL) { GNIX_WARN(FI_LOG_EP_CTRL, "process_datagram, null cache\n"); goto err; } if (state != GNI_POST_COMPLETED) { ret = __process_dgram_w_error(cm_nic, dgram, peer_address, state); GNIX_WARN(FI_LOG_EP_CTRL, "process_datagram bad post state %d\n", state); goto err; } __dgram_get_in_tag(dgram, &in_tag); if ((in_tag != GNIX_CM_NIC_BND_TAG) && (in_tag != GNIX_CM_NIC_WC_TAG)) { GNIX_WARN(FI_LOG_EP_CTRL, "datagram with unknown in tag %d\n", in_tag); goto err; } __dgram_unpack_out_tag(dgram, &out_tag); if ((out_tag != GNIX_CM_NIC_BND_TAG) && (out_tag != GNIX_CM_NIC_WC_TAG)) { GNIX_WARN(FI_LOG_EP_CTRL, "datagram with unknown out tag %d\n", out_tag); goto err; } /* * if out buf actually has data, call consumer's * receive callback */ if (out_tag == GNIX_CM_NIC_BND_TAG) { _gnix_dgram_unpack_buf(dgram, GNIX_DGRAM_OUT_BUF, rcv_buf, GNIX_CM_NIC_MAX_MSG_SIZE); ret = cm_nic->rcv_cb_fn(cm_nic, rcv_buf, peer_address); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "cm_nic->rcv_cb_fn returned %s\n", fi_strerror(-ret)); goto err; } ret = _gnix_cm_nic_progress(cm_nic); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_cm_nic_progress returned %s\n", fi_strerror(-ret)); } /* * if we are processing a WC datagram, repost, otherwise * just put back on the freelist. */ if (in_tag == GNIX_CM_NIC_WC_TAG) { dgram->callback_fn = __process_datagram; dgram->cache = cm_nic; __dgram_set_tag(dgram, in_tag); ret = _gnix_dgram_wc_post(dgram); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_wc_post returned %s\n", fi_strerror(-ret)); goto err; } } else { ret = _gnix_dgram_free(dgram); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_free returned %s\n", fi_strerror(-ret)); } return ret; err: if (in_tag == GNIX_CM_NIC_BND_TAG) _gnix_dgram_free(dgram); return ret; }
int _gnix_cm_nic_enable(struct gnix_cm_nic *cm_nic) { int i, ret = FI_SUCCESS; struct gnix_fid_fabric *fabric; struct gnix_datagram *dg_ptr; uint8_t tag = GNIX_CM_NIC_WC_TAG; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); if (cm_nic == NULL) return -FI_EINVAL; if (cm_nic->domain == NULL) { GNIX_FATAL(FI_LOG_EP_CTRL, "domain is NULL\n"); } if (cm_nic->domain->fabric == NULL) { GNIX_FATAL(FI_LOG_EP_CTRL, "fabric is NULL\n"); } fabric = cm_nic->domain->fabric; assert(cm_nic->dgram_hndl != NULL); for (i = 0; i < fabric->n_wc_dgrams; i++) { ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_WC, &dg_ptr); /* * wildcards may already be posted to the cm_nic, * so just break if -FI_EAGAIN is returned by * _gnix_dgram_alloc */ if (ret == -FI_EAGAIN) { ret = FI_SUCCESS; break; } if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_alloc call returned %d\n", ret); goto err; } dg_ptr->callback_fn = __process_datagram; dg_ptr->cache = cm_nic; __dgram_set_tag(dg_ptr, tag); ret = _gnix_dgram_wc_post(dg_ptr); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_wc_post returned %d\n", ret); _gnix_dgram_free(dg_ptr); goto err; } } /* * TODO: better cleanup in error case */ err: return ret; }
int _gnix_cm_nic_send(struct gnix_cm_nic *cm_nic, char *sbuf, size_t len, struct gnix_address target_addr) { int ret = FI_SUCCESS; struct gnix_datagram *dgram = NULL; ssize_t __attribute__((unused)) plen; uint8_t tag; struct gnix_work_req *work_req; GNIX_TRACE(FI_LOG_EP_CTRL, "\n"); if ((cm_nic == NULL) || (sbuf == NULL)) return -FI_EINVAL; if (len > GNI_DATAGRAM_MAXSIZE) return -FI_ENOSPC; ret = _gnix_dgram_alloc(cm_nic->dgram_hndl, GNIX_DGRAM_BND, &dgram); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_dgram_alloc returned %s\n", fi_strerror(-ret)); goto exit; } dgram->target_addr = target_addr; dgram->callback_fn = __process_datagram; dgram->cache = cm_nic; tag = GNIX_CM_NIC_BND_TAG; __dgram_set_tag(dgram, tag); plen = _gnix_dgram_pack_buf(dgram, GNIX_DGRAM_IN_BUF, sbuf, len); assert (plen == len); /* If connecting with the same CM NIC, skip datagram exchange. The * caller could be holding an endpoint lock, so schedule connection * completion for later. */ if (GNIX_ADDR_EQUAL(target_addr, cm_nic->my_name.gnix_addr)) { char tmp_buf[GNIX_CM_NIC_MAX_MSG_SIZE]; /* Pack output buffer with input data. */ _gnix_dgram_unpack_buf(dgram, GNIX_DGRAM_IN_BUF, tmp_buf, GNIX_CM_NIC_MAX_MSG_SIZE); _gnix_dgram_pack_buf(dgram, GNIX_DGRAM_OUT_BUF, tmp_buf, GNIX_CM_NIC_MAX_MSG_SIZE); work_req = calloc(1, sizeof(*work_req)); if (work_req == NULL) { _gnix_dgram_free(dgram); return -FI_ENOMEM; } work_req->progress_fn = __gnix_cm_nic_intra_progress_fn; work_req->data = dgram; work_req->completer_fn = NULL; fastlock_acquire(&cm_nic->wq_lock); dlist_insert_before(&work_req->list, &cm_nic->cm_nic_wq); fastlock_release(&cm_nic->wq_lock); GNIX_INFO(FI_LOG_EP_CTRL, "Initiated intra-CM NIC connect\n"); } else { ret = _gnix_dgram_bnd_post(dgram); if (ret == -FI_EBUSY) { ret = -FI_EAGAIN; _gnix_dgram_free(dgram); } } exit: return ret; }