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"); }
/* * we unpack the out tag instead of getting it * since we need to pass the partially advanced * out buf to the receive callback function * associated with the cm_nic instance. */ static void __dgram_unpack_out_tag(struct gnix_datagram *d, uint8_t *tag) { _gnix_dgram_rewind_buf(d, GNIX_DGRAM_OUT_BUF); _gnix_dgram_unpack_buf(d, GNIX_DGRAM_OUT_BUF, tag, sizeof(uint8_t)); }
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_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; }