zoukankan      html  css  js  c++  java
  • crc32_offload_api_example

    https://github.com/Mellanox/crc32_offload_api_example

    CC ?= gcc
    
    LDFLAGS += -libverbs
    
    
    TARGETS = ibv_crc32_example
    
    all: $(TARGETS)
    
    ibv_crc32_example: crc32_example.o
    	$(CC) $(LDFLAGS) -o $@ $^
    
    clean:
    	rm -f *.o $(TARGETS)
    

     README

    BUILD
    =====
    
    $ make
    cc    -c -o crc32_example.o crc32_example.c
    cc -libverbs -o ibv_crc32_example crc32_example.o
    
    
    Examples:
    
    # Run the server
    ./ibv_crc32_example -d mlx5_0 -i 1
    
    # Run the initiator
    ./ibv_crc32_example -d mlx5_0 -i 1 11.212.80.5
    
    
    $ ./ibv_crc32_example --help
    Usage:
     ./ibv_crc32_example start a server and wait for connection
     ./ibv_crc32_example <host> connect to server at <host>
    
    Options:
     -p, --port <port>            listen on/connect to port <port> (default 18515)
     -d, --ib-dev <dev>           use IB device <dev> (default first device found)
     -i, --ib-port <port>         use port <port> of IB device (default 1)
     -g, --gid_idx <git index>    gid index to be used in GRH (default not used)
     -b, --block-size <size>      size of data block, only 512 and 4096 are supported (default 512)
     -n, --number-of-blocks <NB>  Number of blocks per RDMA operation (default 8)
     -o, --interleave             Contiguous data segments and signature blocks logically interleaved using UMR capabilities. (disabled by default)
    

     crc32_example.c

    #define _POSIX_C_SOURCE 200809L
    #include <arpa/inet.h>
    #include <byteswap.h>
    #include <endian.h>
    #include <getopt.h>
    #include <infiniband/verbs.h>
    #include <inttypes.h>
    #include <netdb.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    /* poll CQ timeout in millisec (2 seconds) */
    #define MAX_POLL_CQ_TIMEOUT 2000
    /* Protection information size is 4 bytes for CRC32 */
    #define PI_SIZE 4
    
    #if __BYTE_ORDER == __LITTLE_ENDIAN
    static inline uint64_t htonll(uint64_t x)
    {
    	return bswap_64(x);
    }
    static inline uint64_t ntohll(uint64_t x)
    {
    	return bswap_64(x);
    }
    #elif __BYTE_ORDER == __BIG_ENDIAN
    static inline uint64_t htonll(uint64_t x)
    {
    	return x;
    }
    static inline uint64_t ntohll(uint64_t x)
    {
    	return x;
    }
    #else
    #error __BYTE_ORDER is neither __LITTLE_ENDIAN nor __BIG_ENDIAN
    #endif
    
    enum sig_mode {
    	SIG_MODE_INSERT,
    	SIG_MODE_CHECK,
    	SIG_MODE_STRIP,
    };
    
    /* structure of test parameters */
    struct config_t {
    	const char *dev_name;	/* IB device name */
    	char *server_name;	/* server host name */
    	u_int32_t tcp_port;	/* server TCP port */
    	int ib_port;		/* local IB port to work with */
    	int gid_idx;		/* gid index to use */
    	int block_size;
    	int nb;
    	int interleave;
    };
    
    /* structure to exchange data which is needed to connect the QPs */
    struct cm_con_data_t {
    	uint32_t qp_num;
    	uint16_t lid;
    	uint8_t gid[16];
    } __attribute__((packed));
    
    enum msg_types {
    	MSG_TYPE_RDMA_READ_REQ = 0,
    	MSG_TYPE_RDMA_READ_REP,
    	MSG_TYPE_RDMA_WRITE_REQ,
    	MSG_TYPE_RDMA_WRITE_REP,
    	MSG_TYPE_CLOSE_CONN,
    };
    
    enum msg_rep_status {
    	MSG_REP_STATUS_OK = 0,
    	MSG_REP_STATUS_FAIL,
    };
    
    struct msg_t {
    	uint8_t type;
    	union {
    		struct {
    			uint64_t addr; /* Buffer address */
    			uint32_t rkey; /* Remote key */
    		} req;
    		struct {
    			uint32_t status;
    		} rep;
    	} data;
    } __attribute__((packed));
    #define MSG_SIZE (sizeof(struct msg_t))
    
    /* structure of system resources */
    struct resources {
    	struct ibv_device_attr device_attr;
    	/* Device attributes */
    	struct ibv_port_attr port_attr;
    	struct cm_con_data_t remote_props; /* values to connect to remote side */
    	struct ibv_context *ib_ctx;
    	struct ibv_pd *pd;
    	struct ibv_cq *cq;
    	struct ibv_qp *qp;
    
    	struct ibv_mr *send_mr;	/* MR for send buffer */
    	struct ibv_mr *recv_mr;	/* MR for recv buffer */
    	struct ibv_mr *data_mr;	/* MR for data buffer */
    	struct ibv_mr *pi_mr;	/* MR for protection information buffer */
    	struct ibv_mr *sig_mr;	/* signature MR */
    
    	char *send_buf;
    	char *recv_buf;
    	uint8_t *data_buf;
    	size_t data_buf_size;
    	uint8_t *pi_buf;
    	size_t pi_buf_size;
    	int sock; /* TCP socket file descriptor */
    };
    
    struct config_t config = {
    	.dev_name	= NULL,
    	.server_name	= NULL,
    	.tcp_port	= 19875,
    	.ib_port	= 1,
    	.gid_idx	= -1,
    	.block_size	= 512,
    	.nb		= 8,
    	.interleave	= 0
    };
    
    /******************************************************************************
    Socket operations
    For simplicity, the example program uses TCP sockets to exchange control
    information. If a TCP/IP stack/connection is not available, connection manager
    (CM) may be used to pass this information. Use of CM is beyond the scope of
    this example
    ******************************************************************************/
    
    /******************************************************************************
     * Function: sock_connect
     *
     * Input
     * servername URL of server to connect to (NULL for server mode)
     * port port of service
     *
     * Output
     * none
     *
     * Returns
     * socket (fd) on success, negative error code on failure
     *
     * Description
     * Connect a socket. If servername is specified a client connection will be
     * initiated to the indicated server and port. Otherwise listen on the
     * indicated port for an incoming connection.
     *
     ******************************************************************************/
    static int sock_connect(const char *servername, int port)
    {
    	struct addrinfo *resolved_addr = NULL;
    	struct addrinfo *iterator;
    	char service[6];
    	int sockfd = -1;
    	int listenfd = 0;
    	int tmp;
    
    	struct addrinfo hints = { .ai_flags = AI_PASSIVE,
    				  .ai_family = AF_INET,
    				  .ai_socktype = SOCK_STREAM };
    	if (sprintf(service, "%d", port) < 0)
    		goto sock_connect_exit;
    	/* Resolve DNS address, use sockfd as temp storage */
    	sockfd = getaddrinfo(servername, service, &hints, &resolved_addr);
    	if (sockfd) {
    		fprintf(stderr, "%s for %s:%d
    ", gai_strerror(sockfd),
    			servername, port);
    		goto sock_connect_exit;
    	}
    	/* Search through results and find the one we want */
    	for (iterator = resolved_addr; iterator; iterator = iterator->ai_next) {
    		sockfd = socket(iterator->ai_family, iterator->ai_socktype,
    				iterator->ai_protocol);
    		if (sockfd >= 0) {
    			if (servername) {
    				/* Client mode. Initiate connection to remote */
    				if ((tmp = connect(sockfd, iterator->ai_addr,
    						   iterator->ai_addrlen))) {
    					fprintf(stdout, "failed connect 
    ");
    					close(sockfd);
    					sockfd = -1;
    				}
    			} else {
    				/* Server mode. Set up listening socket an accept a connection */
    				listenfd = sockfd;
    				sockfd = -1;
    				if (bind(listenfd, iterator->ai_addr, iterator->ai_addrlen))
    					goto sock_connect_exit;
    
    				listen(listenfd, 1);
    				sockfd = accept(listenfd, NULL, 0);
    			}
    		}
    	}
    
    sock_connect_exit:
    	if (listenfd)
    		close(listenfd);
    	if (resolved_addr)
    		freeaddrinfo(resolved_addr);
    	if (sockfd < 0) {
    		if (servername)
    			fprintf(stderr, "Couldn't connect to %s:%d
    ",
    				servername, port);
    		else {
    			perror("server accept");
    			fprintf(stderr, "accept() failed
    ");
    		}
    	}
    	return sockfd;
    }
    
    /******************************************************************************
     * Function: sock_sync_data
     *
     * Input
     * sock socket to transfer data on
     * xfer_size size of data to transfer
     * local_data pointer to data to be sent to remote
     *
     * Output
     * remote_data pointer to buffer to receive remote data
     *
     * Returns
     * 0 on success, negative error code on failure
     *
     * Description
     * Sync data across a socket. The indicated local data will be sent to the
     * remote. It will then wait for the remote to send its data back. It is
     * assumed that the two sides are in sync and call this function in the proper
     * order. Chaos will ensue if they are not. :)
     *
     * Also note this is a blocking function and will wait for the full data to be
     * received from the remote.
     *
     ******************************************************************************/
    int sock_sync_data(int sock, int xfer_size, char *local_data, char *remote_data)
    {
    	int rc;
    	int read_bytes = 0;
    	int total_read_bytes = 0;
    	rc = write(sock, local_data, xfer_size);
    	if (rc < xfer_size)
    		fprintf(stderr, "Failed writing data during sock_sync_data
    ");
    	else
    		rc = 0;
    	while (!rc && total_read_bytes < xfer_size) {
    		read_bytes = read(sock, remote_data, xfer_size);
    		if (read_bytes > 0)
    			total_read_bytes += read_bytes;
    		else
    			rc = read_bytes;
    	}
    	return rc;
    }
    /******************************************************************************
    End of socket operations
    ******************************************************************************/
    
    /* poll_completion */
    /******************************************************************************
     * Function: poll_completion
     *
     * Input
     * res pointer to resources structure
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, 1 on failure
     *
     * Description
     * Poll the completion queue for a single event. This function will continue to
     * poll the queue until MAX_POLL_CQ_TIMEOUT milliseconds have passed.
     *
     ******************************************************************************/
    static int poll_completion(struct resources *res)
    {
    	struct ibv_wc wc;
    	unsigned long start_time_msec;
    	unsigned long cur_time_msec;
    	struct timeval cur_time;
    	int poll_result;
    	int rc = 0;
    	/* poll the completion for a while before giving up of doing it .. */
    	gettimeofday(&cur_time, NULL);
    	start_time_msec = (cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);
    	do {
    		poll_result = ibv_poll_cq(res->cq, 1, &wc);
    		gettimeofday(&cur_time, NULL);
    		cur_time_msec =
    			(cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);
    	} while ((poll_result == 0) &&
    		 ((cur_time_msec - start_time_msec) < MAX_POLL_CQ_TIMEOUT));
    	if (poll_result < 0) {
    		/* poll CQ failed */
    		fprintf(stderr, "poll CQ failed
    ");
    		rc = 1;
    	} else if (poll_result == 0) {
    		/* the CQ is empty */
    		fprintf(stderr,
    			"completion wasn't found in the CQ after timeout
    ");
    		rc = 1;
    	} else {
    		/* CQE found */
    		fprintf(stdout, "completion was found in CQ with status 0x%x, opcode %u
    ",
    			wc.status, wc.opcode);
    		/* check the completion status (here we don't care about the completion
         * opcode */
    		if (wc.status != IBV_WC_SUCCESS) {
    			fprintf(stderr,
    				"got bad completion with status: 0x%x, vendor syndrome: 0x%x
    ",
    				wc.status, wc.vendor_err);
    			rc = 1;
    		}
    	}
    	return rc;
    }
    
    /******************************************************************************
     * Function: post_send
     *
     * Input
     * res pointer to resources structure
     * opcode IBV_WR_SEND, IBV_WR_RDMA_READ or IBV_WR_RDMA_WRITE
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, error code on failure
     *
     * Description
     * This function will create and post a send work request
     ******************************************************************************/
    static int post_send(struct resources *res, int opcode, const struct msg_t *req)
    {
    	struct ibv_send_wr sr;
    	struct ibv_sge sge;
    	struct ibv_send_wr *bad_wr = NULL;
    	int rc;
    	/* prepare the scatter/gather entry */
    	memset(&sge, 0, sizeof(sge));
    	if (!req) {
    		sge.addr = (uintptr_t)res->send_mr->addr;
    		sge.length = MSG_SIZE;
    		sge.lkey = res->send_mr->lkey;
    	} else {
    		sge.addr = (uintptr_t)res->sig_mr->addr;
    		sge.length = config.block_size * config.nb;
    		sge.lkey = res->sig_mr->lkey;
    	}
    
    	/* prepare the send work request */
    	memset(&sr, 0, sizeof(sr));
    	sr.next = NULL;
    	sr.sg_list = &sge;
    	sr.num_sge = 1;
    	sr.opcode = opcode;
    	sr.send_flags = IBV_SEND_SIGNALED;
    	if (req) {
    		sr.wr.rdma.remote_addr = ntohll(req->data.req.addr);
    		sr.wr.rdma.rkey = ntohl(req->data.req.rkey);
    	}
    	/* there is a Receive Request in the responder side, so we won't get any into
       * RNR flow */
    	rc = ibv_post_send(res->qp, &sr, &bad_wr);
    	if (rc)
    		fprintf(stderr, "failed to post SR
    ");
    	else {
    		switch (opcode) {
    		case IBV_WR_SEND:
    			fprintf(stdout, "Send Request was posted
    ");
    			break;
    		case IBV_WR_RDMA_READ:
    			fprintf(stdout, "RDMA Read Request was posted
    ");
    			break;
    		case IBV_WR_RDMA_WRITE:
    			fprintf(stdout, "RDMA Write Request was posted
    ");
    			break;
    		default:
    			fprintf(stdout, "Unknown Request was posted
    ");
    			break;
    		}
    	}
    	return rc;
    }
    
    /******************************************************************************
     * Function: post_receive
     *
     * Input
     * res pointer to resources structure
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, error code on failure
     *
     * Description
     *
     ******************************************************************************/
    static int post_receive(struct resources *res)
    {
    	struct ibv_recv_wr rr;
    	struct ibv_sge sge;
    	struct ibv_recv_wr *bad_wr;
    	int rc;
    
    	/* prepare the scatter/gather entry */
    	memset(&sge, 0, sizeof(sge));
    	sge.addr = (uintptr_t)res->recv_mr->addr;
    	sge.length = MSG_SIZE;
    	sge.lkey = res->recv_mr->lkey;
    
    	/* prepare the receive work request */
    	memset(&rr, 0, sizeof(rr));
    	rr.sg_list = &sge;
    	rr.num_sge = 1;
    
    	rc = ibv_post_recv(res->qp, &rr, &bad_wr);
    	if (rc)
    		fprintf(stderr, "failed to post RR
    ");
    	else
    		fprintf(stdout, "Receive Request was posted
    ");
    	return rc;
    }
    
    void set_sig_domain_none(struct ibv_exp_sig_domain *sd)
    {
    	memset(sd, 0, sizeof(struct ibv_exp_sig_domain));
    
    	sd->sig_type = IBV_EXP_SIG_TYPE_NONE;
    }
    
    
    void set_sig_domain_crc32(struct ibv_exp_sig_domain *sd)
    {
    	memset(sd, 0, sizeof(struct ibv_exp_sig_domain));
    
    	sd->sig_type = IBV_EXP_SIG_TYPE_CRC32;
    	sd->sig.crc.pi_interval = config.block_size;
    	sd->sig.crc.bg = 0xffffffff;
    }
    
    
    int reg_sig_mr(struct resources *res,
    	       enum sig_mode mode)
    {
    	struct ibv_exp_sig_attrs sig_attrs = {
    		.check_mask = 0xff,
    	};
    	struct ibv_sge data;
    	struct ibv_sge prot;
    	struct ibv_exp_send_wr wr;
    	struct ibv_exp_send_wr *bad_wr;
    	int rc;
    
    	switch (mode) {
    	case SIG_MODE_INSERT:
    	case SIG_MODE_STRIP:
    		set_sig_domain_none(&sig_attrs.mem);
    		set_sig_domain_crc32(&sig_attrs.wire);
    		break;
    	case SIG_MODE_CHECK:
    		set_sig_domain_crc32(&sig_attrs.mem);
    		set_sig_domain_crc32(&sig_attrs.wire);
    		break;
    	default:
    		break;
    	}
    
    	memset(&wr, 0, sizeof(wr));
    	wr.exp_opcode = IBV_EXP_WR_REG_SIG_MR;
    	wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
    	wr.ext_op.sig_handover.sig_attrs = &sig_attrs;
    	wr.ext_op.sig_handover.sig_mr = res->sig_mr;
    	wr.ext_op.sig_handover.access_flags = IBV_ACCESS_LOCAL_WRITE |
    	                                      IBV_ACCESS_REMOTE_READ |
    	                                      IBV_ACCESS_REMOTE_WRITE;
    	data.addr = (uintptr_t)res->data_mr->addr;
    	data.lkey = res->data_mr->lkey;
    	if ((mode == SIG_MODE_INSERT) ||
    	    (mode == SIG_MODE_STRIP) ||
    	    (config.interleave))
    		data.length = config.block_size * config.nb;
    	else
    		data.length = res->data_mr->length;
    	wr.num_sge = 1;
    	wr.sg_list = &data;
    
    	if ((!res->pi_buf) ||
    	    (mode == SIG_MODE_INSERT) ||
    	    (mode == SIG_MODE_STRIP)) {
    		wr.ext_op.sig_handover.prot = NULL;
    	} else {
    		prot.addr = (uint64_t)res->pi_mr->addr;
    		prot.length = res->pi_mr->length;
    		prot.lkey = res->pi_mr->lkey;
    		wr.ext_op.sig_handover.prot = &prot;
    	}
    
    	rc = ibv_exp_post_send(res->qp, &wr, &bad_wr);
    	if (rc) {
    		fprintf(stderr, "post sig mr registration failed
    ");
    		return rc;
    	}
    
    	rc = poll_completion(res);
    	if (rc) {
    		fprintf(stderr, "poll completion failed
    ");
    	}
    
    	fprintf(stdout, "Signature MR was registered with addr=%p, lkey=0x%x, rkey=0x%x
    ",
    		res->sig_mr->addr, res->sig_mr->lkey, res->sig_mr->rkey);
    
    	return rc;
    }
    
    
    int inv_sig_mr(struct resources *res)
    {
    	struct ibv_exp_send_wr wr;
    	struct ibv_exp_send_wr *bad_wr;
    	int rc;
    
    	memset(&wr, 0, sizeof(wr));
    	wr.exp_opcode = IBV_EXP_WR_LOCAL_INV;
    	wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
    	wr.ex.invalidate_rkey = res->sig_mr->rkey;
    
    	rc = ibv_exp_post_send(res->qp, &wr, &bad_wr);
    	if (rc) {
    		fprintf(stderr, "post sig mr ivalidate failed
    ");
    		return rc;
    	}
    
    	rc = poll_completion(res);
    	if (rc) {
    		fprintf(stderr, "poll completion failed
    ");
    	}
    	fprintf(stdout, "Invalidate signature MR rkey=0x%x
    ",
    		res->sig_mr->rkey);
    
    	return rc;
    }
    
    /******************************************************************************
     * Function: resources_init
     *
     * Input
     * res pointer to resources structure
     *
     * Output
     * res is initialized
     *
     * Returns
     * none
     *
     * Description
     * res is initialized to default values
     ******************************************************************************/
    static void resources_init(struct resources *res)
    {
    	memset(res, 0, sizeof *res);
    	res->sock = -1;
    
    	res->data_buf_size = config.block_size * config.nb;
    
    	if (!config.interleave)
    		res->data_buf_size += PI_SIZE * config.nb;
    	else
    		res->pi_buf_size = PI_SIZE * config.nb;
    }
    
    int alloc_and_register_buffer(struct ibv_pd *pd,
    			      size_t size,
    			      void **buf,
    			      struct ibv_mr **mr)
    {
    	int mr_flags = 0;
    
    	if (!size)
    		return 0;
    
    	*buf = malloc(size);
    	if (!*buf) {
    		fprintf(stderr, "failed to malloc %Zu bytes to memory buffer
    ",
    			size);
    		return 1;
    	}
    	memset(*buf, 0, size);
    
    	mr_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ |
    		   IBV_ACCESS_REMOTE_WRITE;
    	*mr = ibv_reg_mr(pd, *buf, size, mr_flags);
    	if (!*mr) {
    		fprintf(stderr, "ibv_reg_mr failed with mr_flags=0x%x
    ",
    			mr_flags);
    		free(*buf);
    		*buf = NULL;
    		return 1;
    	}
    
    	return 0;
    }
    
    /******************************************************************************
     * Function: resources_create
     *
     * Input
     * res pointer to resources structure to be filled in
     *
     * Output
     * res filled in with resources
     *
     * Returns
     * 0 on success, 1 on failure
     *
     * Description
     *
     * This function creates and allocates all necessary system resources. These
     * are stored in res.
     *****************************************************************************/
    
    static int resources_create(struct resources *res)
    {
    	struct ibv_device **dev_list = NULL;
    	struct ibv_exp_qp_init_attr qp_init_attr;
    	struct ibv_device *ib_dev = NULL;
    	struct ibv_exp_create_mr_in sig_mr_in = { };
    
    	size_t size;
    	int i;
    	int cq_size = 0;
    	int num_devices;
    	int rc = 0;
    
    	/* if client side */
    	if (config.server_name) {
    		res->sock = sock_connect(config.server_name, config.tcp_port);
    		if (res->sock < 0) {
    			fprintf(stderr,
    				"failed to establish TCP connection to server %s, port %d
    ",
    				config.server_name, config.tcp_port);
    			rc = -1;
    			goto resources_create_exit;
    		}
    	} else {
    		fprintf(stdout, "waiting on port %d for TCP connection
    ",
    			config.tcp_port);
    		res->sock = sock_connect(NULL, config.tcp_port);
    		if (res->sock < 0) {
    			fprintf(stderr,
    				"failed to establish TCP connection with client on port %d
    ",
    				config.tcp_port);
    			rc = -1;
    			goto resources_create_exit;
    		}
    	}
    
    	fprintf(stdout, "TCP connection was established
    ");
    	fprintf(stdout, "searching for IB devices in host
    ");
    	/* get device names in the system */
    	dev_list = ibv_get_device_list(&num_devices);
    	if (!dev_list) {
    		fprintf(stderr, "failed to get IB devices list
    ");
    		rc = 1;
    		goto resources_create_exit;
    	}
    	/* if there isn't any IB device in host */
    	if (!num_devices) {
    		fprintf(stderr, "found %d device(s)
    ", num_devices);
    		rc = 1;
    		goto resources_create_exit;
    	}
    	fprintf(stdout, "found %d device(s)
    ", num_devices);
    	/* search for the specific device we want to work with */
    	for (i = 0; i < num_devices; i++) {
    		if (!config.dev_name) {
    			config.dev_name =
    				strdup(ibv_get_device_name(dev_list[i]));
    			fprintf(stdout,
    				"device not specified, using first one found: %s
    ",
    				config.dev_name);
    		}
    		if (!strcmp(ibv_get_device_name(dev_list[i]),
    			    config.dev_name)) {
    			ib_dev = dev_list[i];
    			break;
    		}
    	}
    	/* if the device wasn't found in host */
    	if (!ib_dev) {
    		fprintf(stderr, "IB device %s wasn't found
    ", config.dev_name);
    		rc = 1;
    		goto resources_create_exit;
    	}
    	/* get device handle */
    	res->ib_ctx = ibv_open_device(ib_dev);
    	if (!res->ib_ctx) {
    		fprintf(stderr, "failed to open device %s
    ", config.dev_name);
    		rc = 1;
    		goto resources_create_exit;
    	}
    	/* We are now done with device list, free it */
    	ibv_free_device_list(dev_list);
    	dev_list = NULL;
    	ib_dev = NULL;
    
    	/* query port properties */
    	if (ibv_query_port(res->ib_ctx, config.ib_port, &res->port_attr)) {
    		fprintf(stderr, "ibv_query_port on port %u failed
    ",
    			config.ib_port);
    		rc = 1;
    		goto resources_create_exit;
    	}
    	/* allocate Protection Domain */
    	res->pd = ibv_alloc_pd(res->ib_ctx);
    	if (!res->pd) {
    		fprintf(stderr, "ibv_alloc_pd failed
    ");
    		rc = 1;
    		goto resources_create_exit;
    	}
    
    	cq_size = 16;
    	res->cq = ibv_create_cq(res->ib_ctx, cq_size, NULL, NULL, 0);
    	if (!res->cq) {
    		fprintf(stderr, "failed to create CQ with %u entries
    ",
    			cq_size);
    		rc = 1;
    		goto resources_create_exit;
    	}
    
    	rc = alloc_and_register_buffer(res->pd, MSG_SIZE,
    					(void **)&res->send_buf, &res->send_mr);
    	if (rc) {
    		goto resources_create_exit;
    	}
    	rc = alloc_and_register_buffer(res->pd, MSG_SIZE,
    					(void **)&res->recv_buf, &res->recv_mr);
    	if (rc) {
    		goto resources_create_exit;
    	}
    
    	rc = alloc_and_register_buffer(res->pd, res->data_buf_size,
    					(void **)&res->data_buf, &res->data_mr);
    	if (rc) {
    		goto resources_create_exit;
    	}
    
    	rc = alloc_and_register_buffer(res->pd, res->pi_buf_size,
    					(void **)&res->pi_buf, &res->pi_mr);
    	if (rc) {
    		goto resources_create_exit;
    	}
    
    	sig_mr_in.pd = res->pd;
    	sig_mr_in.attr.max_klm_list_size = 1;
    	sig_mr_in.attr.create_flags = IBV_EXP_MR_SIGNATURE_EN;
    	sig_mr_in.attr.exp_access_flags = IBV_ACCESS_LOCAL_WRITE |
    					  IBV_ACCESS_REMOTE_READ |
    					  IBV_ACCESS_REMOTE_WRITE;
    	res->sig_mr = ibv_exp_create_mr(&sig_mr_in);
    	if (!res->sig_mr) {
    		fprintf(stdout, "failed to create the signature
    ");
    		goto resources_create_exit;
    	}
    
    	/* create the Queue Pair */
    	memset(&qp_init_attr, 0, sizeof(qp_init_attr));
    	qp_init_attr.qp_type = IBV_QPT_RC;
    	qp_init_attr.sq_sig_all = 0;
    	qp_init_attr.send_cq = res->cq;
    	qp_init_attr.recv_cq = res->cq;
    	qp_init_attr.cap.max_send_wr = 16;
    	qp_init_attr.cap.max_recv_wr = 1;
    	qp_init_attr.cap.max_send_sge = 1;
    	qp_init_attr.cap.max_recv_sge = 1;
    
    	/* signature specific attributes */
    	qp_init_attr.pd = res->pd;
    	qp_init_attr.comp_mask = IBV_QP_INIT_ATTR_PD;
    	qp_init_attr.comp_mask |= IBV_EXP_QP_INIT_ATTR_CREATE_FLAGS;
    	qp_init_attr.exp_create_flags |= IBV_EXP_QP_CREATE_SIGNATURE_EN;
    	qp_init_attr.exp_create_flags |= IBV_EXP_QP_CREATE_UMR;
    	qp_init_attr.comp_mask |= IBV_EXP_QP_INIT_ATTR_MAX_INL_KLMS;
    	qp_init_attr.max_inl_send_klms = 3;
    	res->qp = ibv_exp_create_qp(res->ib_ctx, &qp_init_attr);
    	if (!res->qp) {
    		fprintf(stderr, "failed to create QP
    ");
    		rc = 1;
    		goto resources_create_exit;
    	}
    	fprintf(stdout, "QP was created, QP number=0x%x
    ", res->qp->qp_num);
    resources_create_exit:
    	if (rc) {
    		/* Error encountered, cleanup */
    		if (res->qp) {
    			ibv_destroy_qp(res->qp);
    			res->qp = NULL;
    		}
    		if (res->sig_mr) {
    			ibv_dereg_mr(res->sig_mr);
    			res->sig_mr = NULL;
    		}
    		if (res->pi_mr) {
    			ibv_dereg_mr(res->pi_mr);
    			res->pi_mr = NULL;
    		}
    		if (res->data_mr) {
    			ibv_dereg_mr(res->data_mr);
    			res->data_mr = NULL;
    		}
    		if (res->send_mr) {
    			ibv_dereg_mr(res->send_mr);
    			res->send_mr = NULL;
    		}
    		if (res->recv_mr) {
    			ibv_dereg_mr(res->recv_mr);
    			res->recv_mr = NULL;
    		}
    		if (res->pi_buf) {
    			free(res->pi_buf);
    			res->pi_buf = NULL;
    		}
    		if (res->data_buf) {
    			free(res->data_buf);
    			res->data_buf = NULL;
    		}
    		if (res->send_buf) {
    			free(res->send_buf);
    			res->send_buf = NULL;
    		}
    		if (res->recv_buf) {
    			free(res->recv_buf);
    			res->recv_buf = NULL;
    		}
    		if (res->cq) {
    			ibv_destroy_cq(res->cq);
    			res->cq = NULL;
    		}
    		if (res->pd) {
    			ibv_dealloc_pd(res->pd);
    			res->pd = NULL;
    		}
    		if (res->ib_ctx) {
    			ibv_close_device(res->ib_ctx);
    			res->ib_ctx = NULL;
    		}
    
    		if (dev_list) {
    			ibv_free_device_list(dev_list);
    			dev_list = NULL;
    		}
    
    		if (res->sock >= 0) {
    			if (close(res->sock))
    				fprintf(stderr, "failed to close socket
    ");
    			res->sock = -1;
    		}
    	}
    	return rc;
    }
    /******************************************************************************
     * Function: modify_qp_to_init
     *
     * Input
     * qp QP to transition
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, ibv_modify_qp failure code on failure
     *
     * Description
     * Transition a QP from the RESET to INIT state
     ******************************************************************************/
    static int modify_qp_to_init(struct ibv_qp *qp)
    {
    	struct ibv_qp_attr attr;
    	int flags;
    	int rc;
    
    	memset(&attr, 0, sizeof(attr));
    	attr.qp_state = IBV_QPS_INIT;
    	attr.port_num = config.ib_port;
    	attr.pkey_index = 0;
    	attr.qp_access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ |
    			       IBV_ACCESS_REMOTE_WRITE;
    	flags = IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT |
    		IBV_QP_ACCESS_FLAGS;
    	rc = ibv_modify_qp(qp, &attr, flags);
    	if (rc)
    		fprintf(stderr, "failed to modify QP state to INIT
    ");
    	return rc;
    }
    
    /******************************************************************************
     * Function: modify_qp_to_rtr
     *
     * Input
     * qp QP to transition
     * remote_qpn remote QP number
     * dlid destination LID
     * dgid destination GID (mandatory for RoCEE)
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, ibv_modify_qp failure code on failure
     *
     * Description
     * Transition a QP from the INIT to RTR state, using the specified QP number
     ******************************************************************************/
    static int modify_qp_to_rtr(struct ibv_qp *qp, uint32_t remote_qpn,
    			    uint16_t dlid, uint8_t *dgid)
    {
    	struct ibv_qp_attr attr;
    	int flags;
    	int rc;
    
    	memset(&attr, 0, sizeof(attr));
    	attr.qp_state = IBV_QPS_RTR;
    	attr.path_mtu = IBV_MTU_256;
    	attr.dest_qp_num = remote_qpn;
    	attr.rq_psn = 0;
    	attr.max_dest_rd_atomic = 1;
    	attr.min_rnr_timer = 0x12;
    	attr.ah_attr.is_global = 0;
    	attr.ah_attr.dlid = dlid;
    	attr.ah_attr.sl = 0;
    	attr.ah_attr.src_path_bits = 0;
    	attr.ah_attr.port_num = config.ib_port;
    	if (config.gid_idx >= 0) {
    		attr.ah_attr.is_global = 1;
    		attr.ah_attr.port_num = 1;
    		memcpy(&attr.ah_attr.grh.dgid, dgid, 16);
    		attr.ah_attr.grh.flow_label = 0;
    		attr.ah_attr.grh.hop_limit = 1;
    		attr.ah_attr.grh.sgid_index = config.gid_idx;
    		attr.ah_attr.grh.traffic_class = 0;
    	}
    	flags = IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN |
    		IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC |
    		IBV_QP_MIN_RNR_TIMER;
    	rc = ibv_modify_qp(qp, &attr, flags);
    	if (rc)
    		fprintf(stderr, "failed to modify QP state to RTR
    ");
    	return rc;
    }
    
    /******************************************************************************
     * Function: modify_qp_to_rts
     *
     * Input
     * qp QP to transition
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, ibv_modify_qp failure code on failure
     *
     * Description
     * Transition a QP from the RTR to RTS state
     ******************************************************************************/
    static int modify_qp_to_rts(struct ibv_qp *qp)
    {
    	struct ibv_qp_attr attr;
    	int flags;
    	int rc;
    	memset(&attr, 0, sizeof(attr));
    	attr.qp_state = IBV_QPS_RTS;
    	attr.timeout = 0x12;
    	attr.retry_cnt = 6;
    	attr.rnr_retry = 0;
    	attr.sq_psn = 0;
    	attr.max_rd_atomic = 1;
    	flags = IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT |
    		IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | IBV_QP_MAX_QP_RD_ATOMIC;
    
    	rc = ibv_modify_qp(qp, &attr, flags);
    	if (rc)
    		fprintf(stderr, "failed to modify QP state to RTS
    ");
    	return rc;
    }
    /******************************************************************************
     * Function: connect_qp
     *
     * Input
     * res pointer to resources structure
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, error code on failure
     *
     * Description
     * Connect the QP. Transition the server side to RTR, sender side to RTS
     ******************************************************************************/
    static int connect_qp(struct resources *res)
    {
    	struct cm_con_data_t local_con_data;
    	struct cm_con_data_t remote_con_data;
    	struct cm_con_data_t tmp_con_data;
    	int rc = 0;
    	char temp_char;
    	union ibv_gid my_gid;
    
    	if (config.gid_idx >= 0) {
    		rc = ibv_query_gid(res->ib_ctx, config.ib_port, config.gid_idx,
    				   &my_gid);
    		if (rc) {
    			fprintf(stderr,
    				"could not get gid for port %d, index %d
    ",
    				config.ib_port, config.gid_idx);
    			return rc;
    		}
    	} else
    		memset(&my_gid, 0, sizeof my_gid);
    	local_con_data.qp_num = htonl(res->qp->qp_num);
    	local_con_data.lid = htons(res->port_attr.lid);
    	memcpy(local_con_data.gid, &my_gid, 16);
    	fprintf(stdout, "
    Local LID = 0x%x
    ", res->port_attr.lid);
    
    	if (sock_sync_data(res->sock, sizeof(struct cm_con_data_t),
    			   (char *)&local_con_data,
    			   (char *)&tmp_con_data) < 0) {
    		fprintf(stderr,
    			"failed to exchange connection data between sides
    ");
    		rc = 1;
    		goto connect_qp_exit;
    	}
    	remote_con_data.qp_num = ntohl(tmp_con_data.qp_num);
    	remote_con_data.lid = ntohs(tmp_con_data.lid);
    	memcpy(remote_con_data.gid, tmp_con_data.gid, 16);
    	/* save the remote side attributes, we will need it for the post SR */
    	res->remote_props = remote_con_data;
    	fprintf(stdout, "Remote QP number = 0x%x
    ", remote_con_data.qp_num);
    	fprintf(stdout, "Remote LID = 0x%x
    ", remote_con_data.lid);
    	if (config.gid_idx >= 0) {
    		uint8_t *p = remote_con_data.gid;
    		fprintf(stdout, "Remote GID = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x
    ",
    			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],p[10], p[11], p[12], p[13], p[14], p[15]);
    	}
    
    	/* modify the QP to init */
    	rc = modify_qp_to_init(res->qp);
    	if (rc) {
    		fprintf(stderr, "change QP state to INIT failed
    ");
    		goto connect_qp_exit;
    	}
    
    	rc = post_receive(res);
    	if (rc) {
    		fprintf(stderr, "failed to post RR
    ");
    		goto connect_qp_exit;
    	}
    	/* modify the QP to RTR */
    	rc = modify_qp_to_rtr(res->qp, remote_con_data.qp_num,
    			      remote_con_data.lid, remote_con_data.gid);
    	if (rc) {
    		fprintf(stderr, "failed to modify QP state to RTR
    ");
    		goto connect_qp_exit;
    	}
    	rc = modify_qp_to_rts(res->qp);
    	if (rc) {
    		fprintf(stderr, "failed to modify QP state to RTR
    ");
    		goto connect_qp_exit;
    	}
    	fprintf(stdout, "QP state was change to RTS
    ");
    	/* sync to make sure that both sides are in states that they can connect to
       * prevent packet loose */
    	if (sock_sync_data(
    		    res->sock, 1, "Q",
    		    &temp_char)) /* just send a dummy char back and forth */
    	{
    		fprintf(stderr, "sync error after QPs are were moved to RTS
    ");
    		rc = 1;
    	}
    connect_qp_exit:
    	return rc;
    }
    
    /******************************************************************************
     * Function: resources_destroy
     *
     * Input
     * res pointer to resources structure
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, 1 on failure
     *
     * Description
     * Cleanup and deallocate all resources used
     ******************************************************************************/
    static int resources_destroy(struct resources *res)
    {
    	int rc = 0;
    	if (res->qp)
    		if (ibv_destroy_qp(res->qp)) {
    			fprintf(stderr, "failed to destroy QP
    ");
    			rc = 1;
    		}
    	if (res->sig_mr)
    		if (ibv_dereg_mr(res->sig_mr)) {
    			fprintf(stderr, "failed to deregister mr
    ");
    			rc = 1;
    		}
    	if (res->pi_mr)
    		if (ibv_dereg_mr(res->pi_mr)) {
    			fprintf(stderr, "failed to deregister mr
    ");
    			rc = 1;
    		}
    	if (res->data_mr)
    		if (ibv_dereg_mr(res->data_mr)) {
    			fprintf(stderr, "failed to deregister mr
    ");
    			rc = 1;
    		}
    	if (res->send_mr)
    		if (ibv_dereg_mr(res->send_mr)) {
    			fprintf(stderr, "failed to deregister mr
    ");
    			rc = 1;
    		}
    	if (res->recv_mr)
    		if (ibv_dereg_mr(res->recv_mr)) {
    			fprintf(stderr, "failed to deregister mr
    ");
    			rc = 1;
    		}
    	if (res->pi_buf)
    		free(res->pi_buf);
    	if (res->data_buf)
    		free(res->data_buf);
    	if (res->send_buf)
    		free(res->send_buf);
    	if (res->recv_buf)
    		free(res->recv_buf);
    	if (res->cq)
    		if (ibv_destroy_cq(res->cq)) {
    			fprintf(stderr, "failed to destroy CQ
    ");
    			rc = 1;
    		}
    	if (res->pd)
    		if (ibv_dealloc_pd(res->pd)) {
    			fprintf(stderr, "failed to deallocate PD
    ");
    			rc = 1;
    		}
    	if (res->ib_ctx)
    		if (ibv_close_device(res->ib_ctx)) {
    			fprintf(stderr, "failed to close device context
    ");
    			rc = 1;
    		}
    
    	if (res->sock >= 0)
    		if (close(res->sock)) {
    			fprintf(stderr, "failed to close socket
    ");
    			rc = 1;
    		}
    	return rc;
    }
    
    int check_sig_mr(struct ibv_mr *mr)
    {
    	struct ibv_exp_mr_status status;
    	int rc;
    
    	rc = ibv_exp_check_mr_status(mr, IBV_EXP_MR_CHECK_SIG_STATUS, &status);
    	if (rc) {
    		fprintf(stderr, "check mr status failed
    ");
    		return rc;
    	}
    
    	rc = status.fail_status;
    	fprintf(stdout, "mr status: %s
    ",
    		(rc ? "SIG ERROR" : "OK"));
    
    	return rc;
    }
    
    int send_repl(struct resources *res, uint8_t type, uint32_t status)
    {
    	struct msg_t *msg;
    	int rc;
    
    	msg = (struct msg_t *)res->send_buf;
    	memset(msg, 0, sizeof(*msg));
    	msg->type = type;
    	msg->data.rep.status = htonl(status);
    
    	rc = post_send(res, IBV_WR_SEND, NULL);
    	if (rc)
    		return rc;
    
    	rc = poll_completion(res);
    	if (rc)
    		return rc;
    
    	return rc;
    }
    
    
    int handle_read_req(struct resources *res,
    		    const struct msg_t *req)
    {
    	int rc = 0;
    
    	rc = reg_sig_mr(res, SIG_MODE_STRIP);
    	if (rc)
    		goto err_exit;
    
    	rc = post_send(res, IBV_WR_RDMA_READ, req);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	rc = check_sig_mr(res->sig_mr);
    	if (rc)
    		goto err_exit;
    
    	rc = inv_sig_mr(res);
    	if (rc)
    		goto err_exit;
    
    	rc = post_receive(res);
    	if (rc)
    		goto err_exit;
    
    	rc = send_repl(res, MSG_TYPE_RDMA_READ_REP, MSG_REP_STATUS_OK);
    err_exit:
    	return rc;
    }
    
    int handle_write_req(struct resources *res,
    		     const struct msg_t *req)
    {
    	int rc = 0;
    
    	rc = reg_sig_mr(res, SIG_MODE_STRIP);
    	if (rc)
    		goto err_exit;
    
    	rc = post_send(res, IBV_WR_RDMA_WRITE, req);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	rc = check_sig_mr(res->sig_mr);
    	if (rc)
    		goto err_exit;
    
    	rc = inv_sig_mr(res);
    	if (rc)
    		goto err_exit;
    
    	rc = post_receive(res);
    	if (rc)
    		goto err_exit;
    
    	rc = send_repl(res, MSG_TYPE_RDMA_WRITE_REP, MSG_REP_STATUS_OK);
    err_exit:
    	return rc;
    }
    
    int server(struct resources *res)
    {
    	int rc = 0;
    	int close_conn = 0;
    	struct msg_t *msg = (struct msg_t *)res->recv_buf;
    
    	while (!close_conn) {
    		rc = poll_completion(res);
    		if (rc)
    			break;
    
    		switch (msg->type) {
    		case MSG_TYPE_RDMA_READ_REQ:
    			rc = handle_read_req(res, msg);
    			if (rc)
    				close_conn = 1;
    			break;
    
    		case MSG_TYPE_RDMA_WRITE_REQ:
    			rc = handle_write_req(res, msg);
    			if (rc)
    				close_conn = 1;
    			break;
    
    		case MSG_TYPE_CLOSE_CONN:
    			close_conn = 1;
    			break;
    
    		case MSG_TYPE_RDMA_READ_REP:
    		case MSG_TYPE_RDMA_WRITE_REP:
    			fprintf(stderr, "invalid message type 0x%x
    ", msg->type);
    			rc = 1;
    			close_conn = 1;
    			break;
    
    		default:
    			fprintf(stderr, "unknown message type 0x%x
    ", msg->type);
    			rc = 1;
    			close_conn = 1;
    		}
    
    	}
    
    err_exit:
    	return rc;
    }
    
    
    int client(struct resources *res)
    {
    	int rc = 0;
    	struct msg_t *msg;
    
    	/* ============ RDMA READ ==========================  */
    	rc = reg_sig_mr(res, SIG_MODE_INSERT);
    	if (rc)
    		goto err_exit;
    
    	msg = (struct msg_t *)res->send_buf;
    	msg->type = MSG_TYPE_RDMA_READ_REQ;
    	msg->data.req.addr = htonll((uintptr_t)res->sig_mr->addr);
    	msg->data.req.rkey = htonl(res->sig_mr->rkey);
    
    	rc = post_send(res, IBV_WR_SEND, NULL);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	msg = (struct msg_t *)res->recv_buf;
    	if (msg->type != MSG_TYPE_RDMA_READ_REP ||
    	    ntohl(msg->data.rep.status) != MSG_REP_STATUS_OK) {
    		fprintf(stderr, "invalid message: type 0x%x, status 0x%x
    ",
    			msg->type, ntohl(msg->data.rep.status));
    		goto err_exit;
    	}
    
    	rc = check_sig_mr(res->sig_mr);
    	if (rc)
    		goto err_exit;
    
    	rc = inv_sig_mr(res);
    	if (rc)
    		goto err_exit;
    
    	/* ============ RDMA WRITE ==========================  */
    
    	rc = post_receive(res);
    	if (rc)
    		goto err_exit;
    
    	rc = reg_sig_mr(res, SIG_MODE_CHECK);
    	if (rc)
    		goto err_exit;
    
    	msg = (struct msg_t *)res->send_buf;
    	msg->type = MSG_TYPE_RDMA_WRITE_REQ;
    	msg->data.req.addr = htonll((uintptr_t)res->sig_mr->addr);
    	msg->data.req.rkey = htonl(res->sig_mr->rkey);
    
    	rc = post_send(res, IBV_WR_SEND, NULL);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    	msg = (struct msg_t *)res->recv_buf;
    	if (msg->type != MSG_TYPE_RDMA_WRITE_REP ||
    	    ntohl(msg->data.rep.status) != MSG_REP_STATUS_OK) {
    		fprintf(stderr, "invalid message: type 0x%x, status 0x%x
    ",
    			msg->type, ntohl(msg->data.rep.status));
    		goto err_exit;
    	}
    
    	rc = check_sig_mr(res->sig_mr);
    	if (rc)
    		goto err_exit;
    
    	rc = inv_sig_mr(res);
    	if (rc)
    		goto err_exit;
    
    	/* ============== Send close connection ===================== */
    
    	msg = (struct msg_t *)res->send_buf;
    	msg->type = MSG_TYPE_CLOSE_CONN;
    	rc = post_send(res, IBV_WR_SEND, NULL);
    	if (rc)
    		goto err_exit;
    
    	rc = poll_completion(res);
    	if (rc)
    		goto err_exit;
    
    err_exit:
    	return rc;
    }
    
    
    static void print_config(void)
    {
    	fprintf(stdout, " ------------------------------------------------
    ");
    	fprintf(stdout, " Device name : "%s"
    ", config.dev_name);
    	fprintf(stdout, " IB port : %u
    ", config.ib_port);
    	if (config.server_name)
    		fprintf(stdout, " IP : %s
    ", config.server_name);
    
    	fprintf(stdout, " TCP port : %u
    ", config.tcp_port);
    	if (config.gid_idx >= 0)
    		fprintf(stdout, " GID index : %u
    ", config.gid_idx);
    
    	fprintf(stdout, " Block size : %u
    ", config.block_size);
    	fprintf(stdout, " Number of blocks : %u
    ", config.nb);
    	fprintf(stdout, " Interleave : %u
    ", config.interleave);
    	fprintf(stdout,
    		" ------------------------------------------------
    
    ");
    }
    /******************************************************************************
     * Function: usage
     *
     * Input
     * argv0 command line arguments
     *
     * Output
     * none
     *
     * Returns
     * none
     *
     * Description
     * print a description of command line syntax
     ******************************************************************************/
    
    static void usage(const char *argv0)
    {
    	fprintf(stdout, "Usage:
    ");
    	fprintf(stdout, " %s start a server and wait for connection
    ", argv0);
    	fprintf(stdout, " %s <host> connect to server at <host>
    ", argv0);
    	fprintf(stdout, "
    ");
    	fprintf(stdout, "Options:
    ");
    	fprintf(stdout,
    		" -p, --port <port>            listen on/connect to port <port> (default 18515)
    ");
    	fprintf(stdout,
    		" -d, --ib-dev <dev>           use IB device <dev> (default first device found)
    ");
    	fprintf(stdout,
    		" -i, --ib-port <port>         use port <port> of IB device (default 1)
    ");
    	fprintf(stdout,
    		" -g, --gid_idx <git index>    gid index to be used in GRH "
    		"(default not used)
    ");
    	fprintf(stdout,
    		" -b, --block-size <size>      size of data block, only 512 and 4096 are supported (default 512)
    ");
    	fprintf(stdout,
    		" -n, --number-of-blocks <NB>  Number of blocks per RDMA operation (default 8)
    ");
    	fprintf(stdout,
    		" -o, --interleave             Contiguous data segments and signature blocks logically interleaved using UMR capabilities. (disabled by default)
    ");
    }
    
    /******************************************************************************
     * Function: main
     *
     * Input
     * argc number of items in argv
     * argv command line parameters
     *
     * Output
     * none
     *
     * Returns
     * 0 on success, 1 on failure
     *
     * Description
     * Main program code
     ******************************************************************************/
    int main(int argc, char *argv[])
    {
    	struct resources res;
    	int rc = 1;
    	char temp_char;
    
    	/* parse the command line parameters */
    	while (1) {
    		int c;
    		static struct option long_options[] = {
    			{ .name = "port",	.has_arg = 1, .val = 'p' },
    			{ .name = "ib-dev",	.has_arg = 1, .val = 'd' },
    			{ .name = "ib-port",	.has_arg = 1, .val = 'i' },
    			{ .name = "gid-idx",	.has_arg = 1, .val = 'g' },
    			{ .name = "block-size",	.has_arg = 1, .val = 'b' },
    			{ .name = "number-of-blocks", .has_arg = 1, .val = 'n' },
    			{ .name = "interleave",	.has_arg = 0, .val = 'o' },
    			{ .name = NULL,		.has_arg = 0, .val = '' }
    		};
    
    		c = getopt_long(argc, argv, "p:d:i:g:b:n:o", long_options, NULL);
    		if (c == -1)
    			break;
    		switch (c) {
    		case 'p':
    			config.tcp_port = strtoul(optarg, NULL, 0);
    			break;
    		case 'd':
    			config.dev_name = strdup(optarg);
    			break;
    		case 'i':
    			config.ib_port = strtoul(optarg, NULL, 0);
    			if (config.ib_port < 0) {
    				usage(argv[0]);
    				return 1;
    			}
    			break;
    		case 'g':
    			config.gid_idx = strtoul(optarg, NULL, 0);
    			if (config.gid_idx < 0) {
    				usage(argv[0]);
    				return 1;
    			}
    			break;
    		case 'b':
    			config.block_size = strtoul(optarg, NULL, 0);
    			if (config.block_size != 512 && config.block_size != 4096) {
    				usage(argv[0]);
    				return 1;
    			}
    			break;
    		case 'n':
    			config.nb = strtoul(optarg, NULL, 0);
    			if (config.nb < 1) {
    				usage(argv[0]);
    				return 1;
    			}
    			break;
    		case 'o':
    			config.interleave = 1;
    			break;
    		default:
    			usage(argv[0]);
    			return 1;
    		}
    	}
    
    	/* parse the last parameter (if exists) as the server name */
    	if (optind == argc - 1)
    		config.server_name = argv[optind];
    	else if (optind < argc) {
    		usage(argv[0]);
    		return 1;
    	}
    
    	print_config();
    
    	resources_init(&res);
    
    	if (resources_create(&res)) {
    		fprintf(stderr, "failed to create resources
    ");
    		goto main_exit;
    	}
    
    	if (connect_qp(&res)) {
    		fprintf(stderr, "failed to connect QPs
    ");
    
    		goto main_exit;
    	}
    
    	if (config.server_name)
    		rc = client(&res);
    	else
    		rc = server(&res);
    
    main_exit:
    	if (resources_destroy(&res)) {
    		fprintf(stderr, "failed to destroy resources
    ");
    		rc = 1;
    	}
    	if (config.dev_name)
    		free((char *)config.dev_name);
    	fprintf(stdout, "
    test result is %d
    ", rc);
    
    	return rc;
    }
    
  • 相关阅读:
    2019-08-10T12:18:27.745963Z 7 [Note] Slave I/O thread for channel '': connected to master 'repl_user@192.168.43.81:3306',replication started in log 'mysql-bin.000001' at position 154 2019-08-10T12:18:
    yum安装的mysql 目录结构
    Starting MySQL.. ERROR! The server quit without updating PID file (/db/data/110.pid).
    CentOS7修改主机名
    使用ssh登陆远程主机
    traceroute命令
    Linux设置开机启动
    检查是否安装服务包
    CSS之盒子模型
    BFC块级格式化上下文
  • 原文地址:https://www.cnblogs.com/ztguang/p/15192095.html
Copyright © 2011-2022 走看看