2 * Unix SMB/CIFS implementation.
3 * Test the infiniband wrapper.
5 * Copyright (C) Sven Oehme <oehmes@de.ibm.com> 2006
7 * Major code contributions by Peter Somogyi <psomogyi@gamax.hu>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <sys/socket.h>
31 #include <arpa/inet.h>
40 #include "lib/events/events.h"
41 #include "ib/ibwrapper.h"
47 struct ibw_initattr
*attrs
;
49 char *opts
; /* option string */
51 struct sockaddr_in
*addrs
; /* dynamic array of dest addrs */
54 unsigned int nsec
; /* delta times between messages in nanosec */
55 unsigned int sleep_usec
; /* microsecs to sleep in the main loop to emulate overloading */
56 uint32_t maxsize
; /* maximum variable message size */
61 int nmsg
; /* number of messages to send (client) */
66 struct ibw_ctx
*ibwctx
;
68 struct timeval start_time
, end_time
;
81 int ibwtest_connect_everybody(struct ibwtest_ctx
*tcx
)
83 struct ibw_conn
*conn
;
84 struct ibwtest_conn
*tconn
= talloc_zero(tcx
, struct ibwtest_conn
);
87 for(i
=0; i
<tcx
->naddrs
; i
++) {
88 conn
= ibw_conn_new(tcx
->ibwctx
, tconn
);
89 if (ibw_connect(conn
, &tcx
->addrs
[i
], tconn
)) {
90 fprintf(stderr
, "ibw_connect error at %d\n", i
);
94 DEBUG(DEBUG_DEBUG
, ("sent %d connect request...\n", tcx
->naddrs
));
99 int ibwtest_send_id(struct ibw_conn
*conn
)
101 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
106 DEBUG(DEBUG_DEBUG
, ("ibwtest_send_id\n"));
107 len
= sizeof(uint32_t)+strlen(tcx
->id
)+2;
108 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
109 DEBUG(DEBUG_ERR
, ("send_id: ibw_alloc_send_buf failed\n"));
113 /* first sizeof(uint32_t) size bytes are for length */
114 *((uint32_t *)buf
) = len
;
115 buf
[sizeof(uint32_t)] = (char)TESTOP_SEND_ID
;
116 strcpy(buf
+sizeof(uint32_t)+1, tcx
->id
);
118 if (ibw_send(conn
, buf
, key
, len
)) {
119 DEBUG(DEBUG_ERR
, ("send_id: ibw_send error\n"));
127 int ibwtest_send_test_msg(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, const char *msg
)
133 if (conn
->state
!=IBWC_CONNECTED
)
134 return 0; /* not yet up */
136 len
= strlen(msg
) + 2 + sizeof(uint32_t);
137 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
138 fprintf(stderr
, "send_test_msg: ibw_alloc_send_buf failed\n");
142 *((uint32_t *)buf
) = len
;
144 p
+= sizeof(uint32_t);
145 p
[0] = (char)TESTOP_SEND_TEXT
;
149 if (ibw_send(conn
, buf
, key
, len
)) {
150 DEBUG(DEBUG_ERR
, ("send_test_msg: ibw_send error\n"));
158 unsigned char ibwtest_fill_random(unsigned char *buf
, uint32_t size
)
161 unsigned char sum
= 0;
165 value
= (unsigned char)(256.0 * (rand() / (RAND_MAX
+ 1.0)));
172 unsigned char ibwtest_get_sum(unsigned char *buf
, uint32_t size
)
175 unsigned char sum
= 0;
184 int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, uint32_t size
)
191 len
= sizeof(uint32_t) + 1 + size
+ 1;
192 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
193 DEBUG(DEBUG_ERR
, ("varsize/ibw_alloc_send_buf failed\n"));
196 *((uint32_t *)buf
) = len
;
197 buf
[sizeof(uint32_t)] = TESTOP_SEND_RND
;
198 sum
= ibwtest_fill_random(buf
+ sizeof(uint32_t) + 1, size
);
199 buf
[sizeof(uint32_t) + 1 + size
] = sum
;
200 if (ibw_send(conn
, buf
, key
, len
)) {
201 DEBUG(DEBUG_ERR
, ("varsize/ibw_send failed\n"));
209 int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
)
214 for(i
=0; i
<tcx
->nmsg
; i
++)
216 //size = (uint32_t)((float)(tcx->maxsize) * (rand() / (RAND_MAX + 1.0)));
217 size
= (uint32_t)((float)(tcx
->maxsize
) * ((float)(i
+1)/(float)tcx
->nmsg
));
218 if (ibwtest_do_varsize_scenario_conn_size(tcx
, conn
, size
))
224 /*int ibwtest_do_varsize_scenario(ibwtest_ctx *tcx)
227 struct ibw_conn *conn;
229 for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
230 if (conn->state==IBWC_CONNECTED) {
231 rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
238 int ibwtest_connstate_handler(struct ibw_ctx
*ctx
, struct ibw_conn
*conn
)
240 struct ibwtest_ctx
*tcx
= NULL
; /* userdata */
241 struct ibwtest_conn
*tconn
= NULL
; /* userdata */
244 tcx
= talloc_get_type(ctx
->ctx_userdata
, struct ibwtest_ctx
);
248 DEBUG(DEBUG_DEBUG
, ("test IBWS_INIT\n"));
251 DEBUG(DEBUG_DEBUG
, ("test IBWS_READY\n"));
253 case IBWS_CONNECT_REQUEST
:
254 DEBUG(DEBUG_DEBUG
, ("test IBWS_CONNECT_REQUEST\n"));
255 tconn
= talloc_zero(conn
, struct ibwtest_conn
);
256 if (ibw_accept(ctx
, conn
, tconn
)) {
257 DEBUG(DEBUG_ERR
, ("error accepting the connect request\n"));
261 DEBUG(DEBUG_DEBUG
, ("test IBWS_STOPPED\n"));
262 tcx
->kill_me
= 1; /* main loop can exit */
265 DEBUG(DEBUG_DEBUG
, ("test IBWS_ERROR\n"));
266 ibw_stop(tcx
->ibwctx
);
275 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
276 switch(conn
->state
) {
278 DEBUG(DEBUG_DEBUG
, ("test IBWC_INIT\n"));
281 if (gettimeofday(&tcx
->start_time
, NULL
)) {
282 DEBUG(DEBUG_ERR
, ("gettimeofday error %d", errno
));
285 ibwtest_send_id(conn
);
287 case IBWC_DISCONNECTED
:
288 DEBUG(DEBUG_DEBUG
, ("test IBWC_DISCONNECTED\n"));
292 DEBUG(DEBUG_DEBUG
, ("test IBWC_ERROR %s\n", ibw_getLastError()));
302 int ibwtest_receive_handler(struct ibw_conn
*conn
, void *buf
, int n
)
304 struct ibwtest_conn
*tconn
;
306 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
310 assert(n
>=sizeof(uint32_t)+1);
311 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
313 op
= (enum testopcode
)((char *)buf
)[sizeof(uint32_t)];
314 if (op
==TESTOP_SEND_ID
) {
315 tconn
->id
= talloc_strdup(tconn
, ((char *)buf
)+sizeof(uint32_t)+1);
317 if (op
==TESTOP_SEND_ID
|| op
==TESTOP_SEND_TEXT
) {
318 DEBUG(DEBUG_DEBUG
, ("[%d]msg from %s: \"%s\"(%d)\n", op
,
319 tconn
->id
? tconn
->id
: "NULL", ((char *)buf
)+sizeof(uint32_t)+1, n
));
322 if (tcx
->is_server
) {
323 if (op
==TESTOP_SEND_RND
) {
325 sum
= ibwtest_get_sum((unsigned char *)buf
+ sizeof(uint32_t) + 1,
326 n
- sizeof(uint32_t) - 2);
327 DEBUG(DEBUG_DEBUG
, ("[%d]msg varsize %u/sum %u from %s\n",
329 n
- sizeof(uint32_t) - 2,
331 tconn
->id
? tconn
->id
: "NULL"));
332 if (sum
!=((unsigned char *)buf
)[n
-1]) {
333 DEBUG(DEBUG_ERR
, ("ERROR: checksum mismatch %u!=%u\n",
334 (uint32_t)sum
, (uint32_t)((unsigned char *)buf
)[n
-1]));
335 ibw_stop(tcx
->ibwctx
);
338 } else if (op
!=TESTOP_SEND_ID
) {
342 /* bounce message regardless what it is */
343 if (ibw_alloc_send_buf(conn
, (void **)&buf2
, &key2
, n
)) {
344 fprintf(stderr
, "ibw_alloc_send_buf error #2\n");
347 memcpy(buf2
, buf
, n
);
348 if (ibw_send(conn
, buf2
, key2
, n
)) {
349 fprintf(stderr
, "ibw_send error #2\n");
354 } else { /* client: */
355 if (op
==TESTOP_SEND_ID
&& tcx
->maxsize
) {
356 /* send them in one blow */
357 rc
= ibwtest_do_varsize_scenario_conn(tcx
, conn
);
362 sprintf(msg
, "hello world %d", tcx
->nmsg
--);
363 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
365 ibw_stop(tcx
->ibwctx
);
379 void ibwtest_timeout_handler(struct event_context
*ev
, struct timed_event
*te
,
380 struct timeval t
, void *private_data
)
382 struct ibwtest_ctx
*tcx
= talloc_get_type(private_data
, struct ibwtest_ctx
);
385 if (!tcx
->is_server
) {
386 struct ibw_conn
*conn
;
389 /* fill it with something variable... */
390 sprintf(msg
, "hello world %d", tcx
->cnt
++);
392 /* send something to everybody... */
393 for(conn
=tcx
->ibwctx
->conn_list
; conn
!=NULL
; conn
=conn
->next
) {
394 if (conn
->state
==IBWC_CONNECTED
) {
395 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
400 } /* else allow main loop run */
403 static struct ibwtest_ctx
*testctx
= NULL
;
405 void ibwtest_sigint_handler(int sig
)
407 DEBUG(DEBUG_ERR
, ("got SIGINT\n"));
409 if (testctx
->ibwctx
->state
==IBWS_READY
||
410 testctx
->ibwctx
->state
==IBWS_CONNECT_REQUEST
||
411 testctx
->ibwctx
->state
==IBWS_ERROR
)
413 if (testctx
->stopping
) {
414 DEBUG(DEBUG_DEBUG
, ("forcing exit...\n"));
415 testctx
->kill_me
= 1;
417 /* mostly expected case */
418 ibw_stop(testctx
->ibwctx
);
419 testctx
->stopping
= 1;
422 testctx
->kill_me
= 1;
426 int ibwtest_parse_attrs(struct ibwtest_ctx
*tcx
, char *optext
,
427 struct ibw_initattr
**pattrs
, int *nattrs
, char op
)
430 int porcess_next
= 1;
432 struct ibw_initattr
*attrs
= NULL
;
435 for(p
= optext
; *p
!='\0'; p
++) {
440 attrs
= (struct ibw_initattr
*)talloc_size(tcx
,
441 n
* sizeof(struct ibw_initattr
));
442 for(p
= optext
; *p
!='\0'; p
++) {
447 fprintf(stderr
, "-%c format error\n", op
);
451 attrs
[i
].value
= q
+ 1;
455 p
= q
; /* ++ at end */
458 *p
= '\0'; /* ++ at end */
468 static int ibwtest_get_address(const char *address
, struct in_addr
*addr
)
470 if (inet_pton(AF_INET
, address
, addr
) <= 0) {
471 struct hostent
*he
= gethostbyname(address
);
472 if (he
== NULL
|| he
->h_length
> sizeof(*addr
)) {
473 DEBUG(DEBUG_ERR
, ("invalid nework address '%s'\n", address
));
476 memcpy(addr
, he
->h_addr
, he
->h_length
);
481 int ibwtest_getdests(struct ibwtest_ctx
*tcx
, char op
)
484 struct ibw_initattr
*attrs
= NULL
;
485 struct sockaddr_in
*p
;
488 tmp
= talloc_strdup(tcx
, optarg
);
489 if (tmp
== NULL
) return -1;
490 /* hack to reuse the above ibw_initattr parser */
491 if (ibwtest_parse_attrs(tcx
, tmp
, &attrs
, &tcx
->naddrs
, op
))
494 tcx
->addrs
= talloc_size(tcx
,
495 tcx
->naddrs
* sizeof(struct sockaddr_in
));
496 for(i
=0; i
<tcx
->naddrs
; i
++) {
498 p
->sin_family
= AF_INET
;
499 if (ibwtest_get_address(attrs
[i
].name
, &p
->sin_addr
))
501 p
->sin_port
= htons(atoi(attrs
[i
].value
));
507 int ibwtest_init_server(struct ibwtest_ctx
*tcx
)
509 if (tcx
->naddrs
!=1) {
510 fprintf(stderr
, "incorrect number of addrs(%d!=1)\n", tcx
->naddrs
);
514 if (ibw_bind(tcx
->ibwctx
, &tcx
->addrs
[0])) {
515 DEBUG(DEBUG_ERR
, ("ERROR: ibw_bind failed\n"));
519 if (ibw_listen(tcx
->ibwctx
, 1)) {
520 DEBUG(DEBUG_ERR
, ("ERROR: ibw_listen failed\n"));
524 /* continued at IBWS_READY */
528 void ibwtest_usage(struct ibwtest_ctx
*tcx
, char *name
)
531 printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name
);
532 printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
533 printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
534 printf("\t-a addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
535 printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx
->nsec
);
536 printf("\t\t send message periodically and endless when nsec is non-zero\n");
537 printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
538 printf("\t-n number of messages to send [default %d]\n", tcx
->nmsg
);
539 printf("\t-l usec time to sleep in the main loop [default %d]\n", tcx
->sleep_usec
);
540 printf("\t-v max variable msg size in bytes [default %d], 0=don't send var. size\n", tcx
->maxsize
);
541 printf("\t-d LogLevel [default %d]\n", LogLevel
);
542 printf("Press ctrl+C to stop the program.\n");
545 int main(int argc
, char *argv
[])
549 struct event_context
*ev
= NULL
;
550 struct ibwtest_ctx
*tcx
= NULL
;
553 tcx
= talloc_zero(NULL
, struct ibwtest_ctx
);
554 memset(tcx
, 0, sizeof(struct ibwtest_ctx
));
559 /* here is the only case we can't avoid using global... */
561 signal(SIGINT
, ibwtest_sigint_handler
);
562 srand((unsigned)time(NULL
));
564 while ((op
=getopt(argc
, argv
, "i:o:d:m:st:n:l:v:a:")) != -1) {
567 tcx
->id
= talloc_strdup(tcx
, optarg
);
570 tcx
->opts
= talloc_strdup(tcx
, optarg
);
571 if (tcx
->opts
) goto cleanup
;
572 if (ibwtest_parse_attrs(tcx
, tcx
->opts
, &tcx
->attrs
,
577 if (ibwtest_getdests(tcx
, op
))
584 tcx
->nsec
= (unsigned int)atoi(optarg
);
587 tcx
->nmsg
= atoi(optarg
);
590 tcx
->sleep_usec
= (unsigned int)atoi(optarg
);
593 tcx
->maxsize
= (unsigned int)atoi(optarg
);
596 LogLevel
= atoi(optarg
);
599 fprintf(stderr
, "ERROR: unknown option -%c\n", (char)op
);
600 ibwtest_usage(tcx
, argv
[0]);
605 ibwtest_usage(tcx
, argv
[0]);
609 ev
= event_context_init(NULL
);
612 tcx
->ibwctx
= ibw_init(tcx
->attrs
, tcx
->nattrs
,
614 ibwtest_connstate_handler
,
615 ibwtest_receive_handler
,
622 rc
= ibwtest_init_server(tcx
);
624 rc
= ibwtest_connect_everybody(tcx
);
628 while(!tcx
->kill_me
&& !tcx
->error
) {
630 event_add_timed(ev
, tcx
, timeval_current_ofs(0, tcx
->nsec
),
631 ibwtest_timeout_handler
, tcx
);
637 usleep(tcx
->sleep_usec
);
640 if (!tcx
->is_server
&& tcx
->nsent
!=0 && !tcx
->error
) {
641 if (gettimeofday(&tcx
->end_time
, NULL
)) {
642 DEBUG(DEBUG_ERR
, ("gettimeofday error %d\n", errno
));
645 usec
= (tcx
->end_time
.tv_sec
- tcx
->start_time
.tv_sec
) * 1000000 +
646 (tcx
->end_time
.tv_usec
- tcx
->start_time
.tv_usec
);
647 printf("usec: %f, nmsg: %d, usec/nmsg: %f\n",
648 usec
, tcx
->nsent
, usec
/(float)tcx
->nsent
);
652 result
= 0; /* everything OK */
659 DEBUG(DEBUG_ERR
, ("exited with code %d\n", result
));