예제 #1
0
static struct fi_info *
fi_ibv_eq_cm_getinfo(struct fi_ibv_fabric *fab, struct rdma_cm_event *event,
		struct fi_info *pep_info)
{
	struct fi_info *info, *fi;
	struct fi_ibv_connreq *connreq;
	const char *devname = ibv_get_device_name(event->id->verbs->device);

	if (strcmp(devname, fab->info->domain_attr->name)) {
		fi = fi_ibv_get_verbs_info(fab->all_infos, devname);
		if (!fi)
			return NULL;
	} else {
		fi = fab->info;
	}

	info = fi_dupinfo(fi);
	if (!info)
		return NULL;

	info->fabric_attr->fabric = &fab->util_fabric.fabric_fid;
	if (!(info->fabric_attr->prov_name = strdup(VERBS_PROV_NAME)))
		goto err;

	ofi_alter_info(info, pep_info, fab->util_fabric.fabric_fid.api_version);

	info->src_addrlen = fi_ibv_sockaddr_len(rdma_get_local_addr(event->id));
	if (!(info->src_addr = malloc(info->src_addrlen)))
		goto err;
	memcpy(info->src_addr, rdma_get_local_addr(event->id), info->src_addrlen);

	info->dest_addrlen = fi_ibv_sockaddr_len(rdma_get_peer_addr(event->id));
	if (!(info->dest_addr = malloc(info->dest_addrlen)))
		goto err;
	memcpy(info->dest_addr, rdma_get_peer_addr(event->id), info->dest_addrlen);

	VERBS_INFO(FI_LOG_CORE, "src_addr: %s:%d\n",
		   inet_ntoa(((struct sockaddr_in *)info->src_addr)->sin_addr),
		   ntohs(((struct sockaddr_in *)info->src_addr)->sin_port));

	VERBS_INFO(FI_LOG_CORE, "dst_addr: %s:%d\n",
		   inet_ntoa(((struct sockaddr_in *)info->dest_addr)->sin_addr),
		   ntohs(((struct sockaddr_in *)info->dest_addr)->sin_port));

	connreq = calloc(1, sizeof *connreq);
	if (!connreq)
		goto err;

	connreq->handle.fclass = FI_CLASS_CONNREQ;
	connreq->id = event->id;
	info->handle = &connreq->handle;
	return info;
err:
	fi_freeinfo(info);
	return NULL;
}
예제 #2
0
/* TODO: This should copy the listening fi_info as the base */
static struct fi_info *
fi_ibv_eq_cm_getinfo(struct fi_ibv_fabric *fab, struct rdma_cm_event *event)
{
	struct fi_info *info, *fi;
	struct fi_ibv_connreq *connreq;

	fi = fi_ibv_get_verbs_info(ibv_get_device_name(event->id->verbs->device));
	if (!fi)
		return NULL;

	info = fi_dupinfo(fi);
	if (!info)
		return NULL;

	info->fabric_attr->fabric = &fab->fabric_fid;
	if (!(info->fabric_attr->prov_name = strdup(VERBS_PROV_NAME)))
		goto err;

	fi_ibv_update_info(NULL, info);

	info->src_addrlen = fi_ibv_sockaddr_len(rdma_get_local_addr(event->id));
	if (!(info->src_addr = malloc(info->src_addrlen)))
		goto err;
	memcpy(info->src_addr, rdma_get_local_addr(event->id), info->src_addrlen);

	info->dest_addrlen = fi_ibv_sockaddr_len(rdma_get_peer_addr(event->id));
	if (!(info->dest_addr = malloc(info->dest_addrlen)))
		goto err;
	memcpy(info->dest_addr, rdma_get_peer_addr(event->id), info->dest_addrlen);

	FI_INFO(&fi_ibv_prov, FI_LOG_CORE, "src_addr: %s:%d\n",
		inet_ntoa(((struct sockaddr_in *)info->src_addr)->sin_addr),
		ntohs(((struct sockaddr_in *)info->src_addr)->sin_port));

	FI_INFO(&fi_ibv_prov, FI_LOG_CORE, "dst_addr: %s:%d\n",
		inet_ntoa(((struct sockaddr_in *)info->dest_addr)->sin_addr),
		ntohs(((struct sockaddr_in *)info->dest_addr)->sin_port));

	connreq = calloc(1, sizeof *connreq);
	if (!connreq)
		goto err;

	connreq->handle.fclass = FI_CLASS_CONNREQ;
	connreq->id = event->id;
	info->handle = &connreq->handle;
	return info;
err:
	fi_freeinfo(info);
	return NULL;
}
예제 #3
0
int fi_ibv_accept_xrc(struct fi_ibv_xrc_ep *ep, int reciprocal,
		      void *param, size_t paramlen)
{
	struct sockaddr *addr;
	struct fi_ibv_connreq *connreq;
	struct rdma_conn_param conn_param = { 0 };
	struct fi_ibv_xrc_cm_data *cm_data = param;
	int ret;

	addr = rdma_get_local_addr(ep->tgt_id);
	if (addr)
		ofi_straddr_dbg(&fi_ibv_prov, FI_LOG_CORE, "src_addr", addr);

	addr = rdma_get_peer_addr(ep->tgt_id);
	if (addr)
		ofi_straddr_dbg(&fi_ibv_prov, FI_LOG_CORE, "dest_addr", addr);

	connreq = container_of(ep->base_ep.info->handle,
			       struct fi_ibv_connreq, handle);
	ret = fi_ibv_ep_create_tgt_qp(ep, connreq->xrc.conn_data);
	if (ret)
		return ret;

	fi_ibv_set_xrc_cm_data(cm_data, connreq->xrc.is_reciprocal,
			       connreq->xrc.conn_tag, connreq->xrc.port,
			       ep->srqn);
	conn_param.private_data = cm_data;
	conn_param.private_data_len = paramlen;
	conn_param.responder_resources = RDMA_MAX_RESP_RES;
	conn_param.initiator_depth = RDMA_MAX_INIT_DEPTH;
	conn_param.flow_control = 1;
	conn_param.rnr_retry_count = 7;
	if (ep->base_ep.srq_ep)
		conn_param.srq = 1;

	/* Shared INI/TGT QP connection use a temporarily reserved QP number
	 * avoid the appearance of being a stale/duplicate IB CM message */
	if (!ep->tgt_id->qp)
		conn_param.qp_num = ep->conn_setup->rsvd_tgt_qpn->qp_num;

	if (connreq->xrc.is_reciprocal)
		fi_ibv_eq_clear_xrc_conn_tag(ep);
	else
		ep->conn_setup->conn_tag = connreq->xrc.conn_tag;

	assert(ep->conn_state == FI_IBV_XRC_UNCONNECTED ||
	       ep->conn_state == FI_IBV_XRC_ORIG_CONNECTED);
	fi_ibv_next_xrc_conn_state(ep);

	ret = rdma_accept(ep->tgt_id, &conn_param);
	if (ret) {
		ret = -errno;
		VERBS_INFO_ERRNO(FI_LOG_EP_CTRL,
				 "XRC TGT, ibv_open_qp", errno);
		fi_ibv_prev_xrc_conn_state(ep);
	}
	free(connreq);
	return ret;
}
예제 #4
0
static int fi_ibv_msg_ep_getname(fid_t ep, void *addr, size_t *addrlen)
{
	struct fi_ibv_msg_ep *_ep;
	struct sockaddr *sa;

	_ep = container_of(ep, struct fi_ibv_msg_ep, ep_fid);
	sa = rdma_get_local_addr(_ep->id);
	return fi_ibv_copy_addr(addr, addrlen, sa);
}
예제 #5
0
static struct fi_info *
__fi_eq_cm_getinfo(struct __fid_fabric *fab, struct rdma_cm_event *event)
{
	struct fi_info *fi;

	fi = calloc(1, sizeof *fi);
	if (!fi)
		return NULL;

	fi->type = FID_MSG;
	if (event->id->verbs->device->transport_type == IBV_TRANSPORT_IWARP) {
		fi->protocol = FI_PROTO_IWARP;
	} else {
		fi->protocol = FI_PROTO_IB_RC;
	}
	fi->ep_cap = FI_MSG | FI_RMA;

	fi->src_addrlen = fi_sockaddr_len(rdma_get_local_addr(event->id));
	if (!(fi->src_addr = malloc(fi->src_addrlen)))
		goto err;
	memcpy(fi->src_addr, rdma_get_local_addr(event->id), fi->src_addrlen);

	fi->dest_addrlen = fi_sockaddr_len(rdma_get_peer_addr(event->id));
	if (!(fi->dest_addr = malloc(fi->dest_addrlen)))
		goto err;
	memcpy(fi->dest_addr, rdma_get_peer_addr(event->id), fi->dest_addrlen);

	if (!(fi->fabric_name = strdup(fab->name)))
		goto err;

	if (!(fi->domain_name = strdup(event->id->verbs->device->name)))
		goto err;

	fi->datalen = sizeof event->id;
	fi->data = event->id;
	return fi;
err:
	fi_freeinfo(fi);
	return NULL;
}
예제 #6
0
/*
 * svc_rdma_ncreate: waits for connection request and returns transport
 */
SVCXPRT *
svc_rdma_ncreate(void *arg, const u_int sendsize, const u_int recvsize,
		 const u_int flags)
{
	struct svc_rdma_xdr *sm;
	struct sockaddr_storage *ss;
	RDMAXPRT *l_xprt = arg;
	RDMAXPRT *xprt = rpc_rdma_accept_wait(l_xprt, l_xprt->xa->timeout);

	if (!xprt) {
		__warnx(TIRPC_DEBUG_FLAG_ERROR,
			"%s:%u ERROR (return)",
			__func__, __LINE__);
		return (NULL);
	}

	sm = mem_zalloc(sizeof (*sm));

	sm->sm_xdrs.x_lib[1] = xprt;
	xprt->xprt.xp_p2 = sm;

	xprt->xprt.xp_flags = flags;
	/* fixme: put something here, but make it not work on fd operations. */
	xprt->xprt.xp_fd = -1;

	ss = (struct sockaddr_storage *)rdma_get_local_addr(xprt->cm_id);
	__rpc_set_address(&xprt->xprt.xp_local, ss, 0);

	ss = (struct sockaddr_storage *)rdma_get_peer_addr(xprt->cm_id);
	__rpc_set_address(&xprt->xprt.xp_remote, ss, 0);

	svc_rdma_ops(&xprt->xprt);

	if (xdr_rdma_create(&sm->sm_xdrs, xprt, sendsize, recvsize, flags)) {
		goto freedata;
	}

	if (rpc_rdma_accept_finalize(xprt)) {
		goto freedata;
	}

	return (&xprt->xprt);

freedata:
	mem_free(sm, sizeof (*sm));
	xprt->xprt.xp_p2 = NULL;
	xprt_unregister(&xprt->xprt);
	return (NULL);
}
예제 #7
0
static int fi_ibv_pep_listen(struct fid_pep *pep_fid)
{
	struct fi_ibv_pep *pep;
	struct sockaddr *addr;

	pep = container_of(pep_fid, struct fi_ibv_pep, pep_fid);

	addr = rdma_get_local_addr(pep->id);
	if (addr) {
		FI_INFO(&fi_ibv_prov, FI_LOG_CORE, "Listening on %s:%d\n",
			inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
			ntohs(((struct sockaddr_in *)addr)->sin_port));
	}

	return rdma_listen(pep->id, pep->backlog) ? -errno : 0;
}
예제 #8
0
void fi_ibv_log_ep_conn(struct fi_ibv_xrc_ep *ep, char *desc)
{
	struct sockaddr *addr;
	char buf[OFI_ADDRSTRLEN];
	size_t len = sizeof(buf);

	if (!fi_log_enabled(&fi_ibv_prov, FI_LOG_INFO, FI_LOG_FABRIC))
		return;

	VERBS_INFO(FI_LOG_FABRIC, "EP %p, %s\n", ep, desc);
	VERBS_INFO(FI_LOG_FABRIC,
		  "EP %p, CM ID %p, TGT CM ID %p, SRQN %d Peer SRQN %d\n",
		  ep, ep->base_ep.id, ep->tgt_id, ep->srqn, ep->peer_srqn);

	assert(ep->base_ep.id);

	addr = rdma_get_local_addr(ep->base_ep.id);
	if (addr) {
		ofi_straddr(buf, &len, ep->base_ep.info->addr_format, addr);
		VERBS_INFO(FI_LOG_FABRIC, "EP %p src_addr: %s\n", ep, buf);
	}
	addr = rdma_get_peer_addr(ep->base_ep.id);
	if (addr) {
		len = sizeof(buf);
		ofi_straddr(buf, &len, ep->base_ep.info->addr_format, addr);
		VERBS_INFO(FI_LOG_FABRIC, "EP %p dst_addr: %s\n", ep, buf);
	}

	if (ep->base_ep.ibv_qp) {
		VERBS_INFO(FI_LOG_FABRIC, "EP %p, INI QP Num %d\n",
			  ep, ep->base_ep.ibv_qp->qp_num);
		VERBS_INFO(FI_LOG_FABRIC, "EP %p, Remote TGT QP Num %d\n", ep,
			  ep->ini_conn->tgt_qpn);
	}
	if (ep->tgt_ibv_qp)
		VERBS_INFO(FI_LOG_FABRIC, "EP %p, TGT QP Num %d\n",
			  ep, ep->tgt_ibv_qp->qp_num);
	if (ep->conn_setup && ep->conn_setup->rsvd_ini_qpn)
		VERBS_INFO(FI_LOG_FABRIC, "EP %p, Reserved INI QPN %d\n",
			  ep, ep->conn_setup->rsvd_ini_qpn->qp_num);
	if (ep->conn_setup && ep->conn_setup->rsvd_tgt_qpn)
		VERBS_INFO(FI_LOG_FABRIC, "EP %p, Reserved TGT QPN %d\n",
			  ep, ep->conn_setup->rsvd_tgt_qpn->qp_num);
}
예제 #9
0
static int
fi_ibv_msg_ep_connect(struct fid_ep *ep, const void *addr,
		   const void *param, size_t paramlen)
{
	struct fi_ibv_msg_ep *_ep;
	struct rdma_conn_param conn_param;
	struct sockaddr *src_addr, *dst_addr;
	int ret;

	_ep = container_of(ep, struct fi_ibv_msg_ep, ep_fid);
	if (!_ep->id->qp) {
		ret = ep->fid.ops->control(&ep->fid, FI_ENABLE, NULL);
		if (ret)
			return ret;
	}

	memset(&conn_param, 0, sizeof conn_param);
	conn_param.private_data = param;
	conn_param.private_data_len = paramlen;
	conn_param.responder_resources = RDMA_MAX_RESP_RES;
	conn_param.initiator_depth = RDMA_MAX_INIT_DEPTH;
	conn_param.flow_control = 1;
	conn_param.retry_count = 15;
	conn_param.rnr_retry_count = 7;

	if (_ep->srq_ep)
		conn_param.srq = 1;

	src_addr = rdma_get_local_addr(_ep->id);
	if (src_addr) {
		FI_INFO(&fi_ibv_prov, FI_LOG_CORE, "src_addr: %s:%d\n",
			inet_ntoa(((struct sockaddr_in *)src_addr)->sin_addr),
			ntohs(((struct sockaddr_in *)src_addr)->sin_port));
	}

	dst_addr = rdma_get_peer_addr(_ep->id);
	if (dst_addr) {
		FI_INFO(&fi_ibv_prov, FI_LOG_CORE, "dst_addr: %s:%d\n",
			inet_ntoa(((struct sockaddr_in *)dst_addr)->sin_addr),
			ntohs(((struct sockaddr_in *)dst_addr)->sin_port));
	}

	return rdma_connect(_ep->id, &conn_param) ? -errno : 0;
}
예제 #10
0
int fi_ibv_connect_xrc(struct fi_ibv_xrc_ep *ep, struct sockaddr *addr,
		       int reciprocal, void *param, size_t paramlen)
{
	struct fi_ibv_domain *domain = fi_ibv_ep_to_domain(&ep->base_ep);
	struct sockaddr *peer_addr;
	int ret;

	assert(ep->base_ep.id && !ep->base_ep.ibv_qp && !ep->ini_conn);

	peer_addr = rdma_get_local_addr(ep->base_ep.id);
	if (peer_addr)
		ofi_straddr_dbg(&fi_ibv_prov, FI_LOG_FABRIC,
				"XRC connect src_addr", peer_addr);

	peer_addr = rdma_get_peer_addr(ep->base_ep.id);
	if (peer_addr)
		ofi_straddr_dbg(&fi_ibv_prov, FI_LOG_FABRIC,
				"XRC connect dest_addr", peer_addr);

	if (!reciprocal) {
		ep->conn_setup = calloc(1, sizeof(*ep->conn_setup));
		if (!ep->conn_setup)
			return -FI_ENOMEM;
	}

	fastlock_acquire(&domain->xrc.ini_mgmt_lock);
	ret = fi_ibv_get_shared_ini_conn(ep, &ep->ini_conn);
	if (ret) {
		VERBS_WARN(FI_LOG_FABRIC,
			   "Get of shared XRC INI connection failed %d\n", ret);
		fastlock_release(&domain->xrc.ini_mgmt_lock);
		if (!reciprocal) {
			free(ep->conn_setup);
			ep->conn_setup = NULL;
		}
		return ret;
	}
	fi_ibv_add_pending_ini_conn(ep, reciprocal, param, paramlen);
	fi_ibv_sched_ini_conn(ep->ini_conn);
	fastlock_release(&domain->xrc.ini_mgmt_lock);

	return FI_SUCCESS;
}
예제 #11
0
int fi_ibv_create_ep(const char *node, const char *service,
		     uint64_t flags, const struct fi_info *hints,
		     struct rdma_addrinfo **rai, struct rdma_cm_id **id)
{
	struct rdma_addrinfo *_rai;
	struct sockaddr *local_addr;
	int ret;

	ret = fi_ibv_get_rdma_rai(node, service, flags, hints, &_rai);
	if (ret) {
		return ret;
	}

	ret = rdma_create_ep(id, _rai, NULL, NULL);
	if (ret) {
		VERBS_INFO_ERRNO(FI_LOG_FABRIC, "rdma_create_ep", errno);
		ret = -errno;
		goto err1;
	}
	if (rai && !_rai->ai_src_addr) {
		local_addr = rdma_get_local_addr(*id);
		_rai->ai_src_len = fi_ibv_sockaddr_len(local_addr);
		if (!(_rai->ai_src_addr = malloc(_rai->ai_src_len))) {
			ret = -FI_ENOMEM;
			goto err2;
		}
		memcpy(_rai->ai_src_addr, local_addr, _rai->ai_src_len);
	}

	if (rai) {
		*rai = _rai;
	} else {
		rdma_freeaddrinfo(_rai);
	}

	return ret;
err2:
	rdma_destroy_ep(*id);
err1:
	rdma_freeaddrinfo(_rai);

	return ret;
}
예제 #12
0
파일: kiro-server.c 프로젝트: IMCG/kiro
int
kiro_server_start (KiroServer *self, const char *address, const char *port, void *mem, size_t mem_size)
{
    g_return_val_if_fail (self != NULL, -1);
    KiroServerPrivate *priv = KIRO_SERVER_GET_PRIVATE (self);

    if (priv->base) {
        g_debug ("Server already started.");
        return -1;
    }

    if (!mem || mem_size == 0) {
        g_warning ("Invalid memory given to provide.");
        return -1;
    }

    struct rdma_addrinfo hints, *res_addrinfo;
    memset (&hints, 0, sizeof (hints));
    hints.ai_port_space = RDMA_PS_IB;
    hints.ai_flags = RAI_PASSIVE;

    char *addr_c = g_strdup (address);
    char *port_c = g_strdup (port);

    int rtn = rdma_getaddrinfo (addr_c, port_c, &hints, &res_addrinfo);
    g_free (addr_c);
    g_free (port_c);

    if (rtn) {
        g_critical ("Failed to create address information: %s", strerror (errno));
        return -1;
    }

    struct ibv_qp_init_attr qp_attr;
    memset (&qp_attr, 0, sizeof (qp_attr));
    qp_attr.cap.max_send_wr = 10;
    qp_attr.cap.max_recv_wr = 10;
    qp_attr.cap.max_send_sge = 1;
    qp_attr.cap.max_recv_sge = 1;
    qp_attr.qp_context = priv->base;
    qp_attr.sq_sig_all = 1;

    if (rdma_create_ep (& (priv->base), res_addrinfo, NULL, &qp_attr)) {
        g_critical ("Endpoint creation failed: %s", strerror (errno));
        g_free (res_addrinfo);
        return -1;
    }
    g_free (res_addrinfo); // No longer needed

    g_debug ("Endpoint created");
    char *addr_local = NULL;
    struct sockaddr *src_addr = rdma_get_local_addr (priv->base);

    if (!src_addr) {
        addr_local = "NONE";
    }
    else {
        addr_local = inet_ntoa (((struct sockaddr_in *)src_addr)->sin_addr);
        /*
        if(src_addr->sa_family == AF_INET)
            addr_local = &(((struct sockaddr_in*)src_addr)->sin_addr);
        else
            addr_local = &(((struct sockaddr_in6*)src_addr)->sin6_addr);
        */
    }

    g_message ("Server bound to address %s:%s", addr_local, port);

    if (rdma_listen (priv->base, 0)) {
        g_critical ("Failed to put server into listening state: %s", strerror (errno));
        rdma_destroy_ep (priv->base);
        return -1;
    }

    priv->mem = mem;
    priv->mem_size = mem_size;
    priv->ec = rdma_create_event_channel();

    if (rdma_migrate_id (priv->base, priv->ec)) {
        g_critical ("Was unable to migrate connection to new Event Channel: %s", strerror (errno));
        rdma_destroy_ep (priv->base);
        return -1;
    }

    priv->main_loop = g_main_loop_new (NULL, FALSE);
    priv->conn_ec = g_io_channel_unix_new (priv->ec->fd);
    g_io_add_watch (priv->conn_ec, G_IO_IN | G_IO_PRI, process_cm_event, (gpointer)priv);
    priv->main_thread = g_thread_new ("KIRO Server main loop", start_server_main_loop, priv->main_loop);

    // We gave control to the main_loop (with add_watch) and don't need our ref
    // any longer
    g_io_channel_unref (priv->conn_ec);


    g_message ("Enpoint listening");
    return 0;
}
예제 #13
0
static int xrc_test(void)
{
	struct rdma_cm_id *conn_id, *lookup_id;
	struct ibv_qp_init_attr attr;
	struct rdma_conn_param param;
	struct rdma_cm_event *event;
	struct ibv_wc wc;
	int ret;

	conn_id = xrc_listen_recv();
	if (!conn_id)
		return -1;

	ret = xrc_create_srq_listen(rdma_get_local_addr(conn_id),
				    sizeof(struct sockaddr_storage));
	if (ret)
		return -1;

	memset(&attr, 0, sizeof attr);
	attr.qp_type = IBV_QPT_XRC_RECV;
	attr.ext.xrc_recv.xrcd = srq_id->srq->ext.xrc.xrcd;
	ret = rdma_create_qp(conn_id, NULL, &attr);
	if (ret) {
		printf("Unable to create xrc recv qp %d\n", errno);
		return ret;
	}

	ret = rdma_accept(conn_id, NULL);
	if (ret) {
		printf("rdma_accept failed for xrc recv qp %d\n", errno);
		return ret;
	}

	ret = rdma_get_request(srq_id, &lookup_id);
	if (ret) {
		printf("rdma_get_request %d\n", errno);
		return ret;
	}

	mr = rdma_reg_msgs(srq_id, recv_msg, sizeof recv_msg);
	if (!mr) {
		printf("ibv_reg_msgs %d\n", errno);
		return ret;
	}

	ret = rdma_post_recv(srq_id, NULL, recv_msg, sizeof recv_msg, mr);
	if (ret) {
		printf("rdma_post_recv %d\n", errno);
		return ret;
	}

	memset(&param, 0, sizeof param);
	param.qp_num = srq_id->srq->ext.xrc.srq_num;
	ret = rdma_accept(lookup_id, &param);
	if (ret) {
		printf("rdma_accept failed for srqn lookup %d\n", errno);
		return ret;
	}

	rdma_destroy_id(lookup_id);

	ret = rdma_get_recv_comp(srq_id, &wc);
	if (ret <= 0) {
		printf("rdma_get_recv_comp %d\n", ret);
		return ret;
	}

	ret = rdma_get_cm_event(conn_id->channel, &event);
	if (ret || event->event != RDMA_CM_EVENT_DISCONNECTED) {
		printf("Failed to get disconnect event\n");
		return -1;
	}

	rdma_ack_cm_event(event);
	rdma_disconnect(conn_id);
	rdma_destroy_ep(conn_id);
	rdma_dereg_mr(mr);
	rdma_destroy_ep(srq_id);
	rdma_destroy_ep(listen_id);
	return 0;
}