ZBLOG

linux用TCP的RDMA实现的代码

以下是一个使用TCP的RDMA实现的示例代码。该代码使用了OFED和libibverbs库,需要在编译前安装这些依赖项。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rdma/rdma_cma.h>

#define BUF_SIZE 4096

struct rdma_conn {
    struct ibv_context *context;
    struct rdma_cm_id *id;
    struct ibv_pd *pd;
    struct ibv_comp_channel *channel;
    struct ibv_cq *cq;
    struct ibv_qp_init_attr qp_init_attr;
    struct ibv_qp *qp;
    int connected;
};

void on_completion(struct ibv_wc *wc);
int post_receive(struct rdma_conn *conn);
int send_data(struct rdma_conn *conn, char *buf, size_t size);

int main(int argc, char **argv)
{
    if (argc != 3) {
        printf("Usage: %s [server_ip] [server_port]\n", argv[0]);
        return -1;
    }

    const char* server_ip = argv[1];
    const uint16_t server_port = atoi(argv[2]);

    // initialize RDMA resources
    struct rdma_conn conn = {0};
    
    // create context
    conn.context = ibv_open_device();
    
	// create protection domain
	conn.pd = ibv_alloc_pd(conn.context);
	
	// create completion channel
	conn.channel = ibv_create_comp_channel(conn.context);
	
	// create completion queue
	conn.cq = ibv_create_cq(conn.context, 10, NULL, conn.channel, 0);

	// create QP init attributes
	memset(&conn.qp_init_attr, 0, sizeof(conn.qp_init_attr));
	conn.qp_init_attr.send_cq = conn.cq;
	conn.qp_init_attr.recv_cq = conn.cq;
	conn.qp_init_attr.cap.max_send_wr = 10;
	conn.qp_init_attr.cap.max_recv_wr = 10;
	conn.qp_init_attr.cap.max_send_sge = 1;
	conn.qp_init_attr.cap.max_recv_sge = 1;
	conn.qp_init_attr.cap.max_inline_data = BUF_SIZE;

	// create QP
	int ret = rdma_create_qp(NULL, conn.pd, &conn.qp_init_attr);
	if (ret) {
		printf("rdma_create_qp failed: %d\n", ret);
		return -1;
	}
    conn.qp = ret;

    // resolve destination address
    struct sockaddr_in sin = {0};
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(server_ip);
    sin.sin_port = htons(server_port);

    struct rdma_addrinfo hints = {0};
	hints.ai_flags |= RAI_PASSIVE;
	hints.ai_port_space = RDMA_PS_TCP;

	struct rdma_addrinfo *rai_list, *rai_ptr;

	ret = rdma_getaddrinfo((char*)server_ip, NULL, &hints, &rai_list);
	if (ret) {
        printf("rdma_getaddrinfo error: %d\n", ret);
        return -1;
    }

	for (rai_ptr=rai_list; rai_ptr!=NULL; rai_ptr=rai_ptr->ai_next) {
		ret = rdma_resolve_addr(conn.id, NULL,
                                 rai_ptr->ai_dst_addr,
                                 RDMA_DEFAULT_TIMEOUT_MS);
		if (!ret) break;
	}

	rdma_freeaddrinfo(rai_list);

	if (ret) {
        printf("rdma_resolve_addr error: %d\n", ret);
        return -1;
    }

    // resolve route
	ret = rdma_resolve_route(conn.id, RDMA_DEFAULT_TIMEOUT_MS);
	if (ret) {
        printf("rdma_resolve_route error: %d\n", ret);
        return -1;
    }

    // wait for connection
	struct rdma_cm_event *event;
	ret = rdma_get_cm_event(conn.channel, &event);
	if (ret) {
		printf("rdma_get_cm_event failed: %d\n", ret);
		return -1;
	}

	rdma_ack_cm_event(event);

	if (event->event != RDMA_CM_EVENT_ESTABLISHED) {
		printf("Unexpected event: %s (%d)\n",
               rdma_event_str(event->event), event->event);
		return -1;
	}

	conn.connected = 1;

    // post receive operations
    char recv_buf[BUF_SIZE] = {0};
    struct ibv_mr *recv_mr = ibv_reg_mr(conn.pd, recv_buf, BUF_SIZE,
                                        IBV_ACCESS_LOCAL_WRITE |
                                        IBV_ACCESS_REMOTE_WRITE |
                                        IBV_ACCESS_REMOTE_READ);

    if (!recv_mr) {
        printf("ibv_reg_mr failed\n");
        return -1;
    }

    for (int i=0; i<10; ++i) {
        post_receive(&conn);
    }

    // send data
	char* send_buf = "Hello RDMA!";
	size_t send_size = strlen(send_buf)+1;

	send_data(&conn, send_buf, send_size);

	printf("[INFO] Data sent: %s\n", send_buf);

	sleep(3);

	// cleanup
	rdma_disconnect(conn.id);
	rdma_destroy_qp(conn.id);
	rdma_destroy_id(conn.id);
	ibv_dereg_mr(recv_mr);
	ibv_destroy_qp(conn.qp);
	ibv_destroy_cq(conn.cq);
	ibv_destroy_comp_channel(conn.channel);
	ibv_dealloc_pd(conn.pd);
    ibv_close_device(conn.context);

	return 0;
}

void on_completion(struct ibv_wc *wc)
{
	printf("[INFO] Operation completed: %s (%d)\n",
           ibv_wc_status_str(wc->status), wc->status);

	if (wc->opcode & IBV_WC_RECV) {
        printf("[INFO] Received data: %s\n", (char*)wc->wr_id);
        post_receive((struct rdma_conn*)wc->wr_id);
    }
}

int post_receive(struct rdma_conn *conn)
{
	struct ibv_sge sge = {0};
	sge.addr = (uintptr_t)malloc(BUF_SIZE);
	sge.length = BUF_SIZE;
	sge.lkey = ibv_reg_mr(conn->pd, sge.addr, sge.length,
                          IBV_ACCESS_LOCAL_WRITE |
                          IBV_ACCESS_REMOTE_WRITE |
                          IBV_ACCESS_REMOTE_READ)->lkey;

	struct ibv_recv_wr wr = {0};
	wr.sg_list = &sge;
	wr.num_sge = 1;

	struct ibv_recv_wr *bad_wr;
	int ret = ibv_post_recv(conn->qp, &wr, &bad_wr);

	if (ret) {
        printf("ibv_post_recv failed: %d\n", ret);
        return -1;
    }

	return 0;
}

int send_data(struct rdma_conn *conn, char *buf, size_t size)
{
	struct ibv_sge sglist[2] = {0};
	struct ibv_send_wr wr = {0};

	char* send_buf = malloc(size + 1);
	memcpy(send_buf, buf, size+1);

	sglist[0].addr = (uintptr_t)send_buf;
	sglist[0].length = size + 1;
	sglist[0].lkey = ibv_reg_mr(conn->pd, send_buf,
                                sglist[0].length,
                                IBV_ACCESS_LOCAL_WRITE |
                                IBV_ACCESS_REMOTE_READ)->lkey;

	wr.sg_list = sglist;
	wr.num_sge = 1;
	wr.opcode = IBV_WR_SEND;
	wr.send_flags = IBV_SEND_SIGNALED;

	struct ibv_send_wr *bad_wr;
	int ret = ibv_post_send(conn->qp, &wr, &bad_wr);

	if (ret) {
        printf("ibv_post_send failed: %d\n", ret);
        return -1;
    }

	return 0;
}

该代码实现了一个客户端程序,连接到指定的服务器,并通过RDMA协议发送数据。具体来说,它首先创建了RDMA资源(包括上下文、保护域、完成通道、完成队列和QP等),然后解析远程地址并建立连接。在连接建立之后,它向服务器发送一条消息,并等待回复。最后,它清理所有资源并退出程序。

需要注意的是,在使用RDMA协议时需要仔细管理内存区域和注册的MR(内存区域)对象。另外,在这个例子中我们只实现了基本的发送和接收操作,实际应用中还需要考虑更多因素(例如错误处理、流量控制等)。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=1577

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?