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 "ib/ibwrapper.h"
46 struct ibw_initattr
*attrs
;
48 char *opts
; /* option string */
50 struct sockaddr_in
*addrs
; /* dynamic array of dest addrs */
53 unsigned int nsec
; /* delta times between messages in nanosec */
54 unsigned int sleep_usec
; /* microsecs to sleep in the main loop to emulate overloading */
55 uint32_t maxsize
; /* maximum variable message size */
60 int nmsg
; /* number of messages to send (client) */
65 struct ibw_ctx
*ibwctx
;
67 struct timeval start_time
, end_time
;
80 int ibwtest_connect_everybody(struct ibwtest_ctx
*tcx
)
82 struct ibw_conn
*conn
;
83 struct ibwtest_conn
*tconn
= talloc_zero(tcx
, struct ibwtest_conn
);
86 for(i
=0; i
<tcx
->naddrs
; i
++) {
87 conn
= ibw_conn_new(tcx
->ibwctx
, tconn
);
88 if (ibw_connect(conn
, &tcx
->addrs
[i
], tconn
)) {
89 fprintf(stderr
, "ibw_connect error at %d\n", i
);
93 DEBUG(DEBUG_DEBUG
, ("sent %d connect request...\n", tcx
->naddrs
));
98 int ibwtest_send_id(struct ibw_conn
*conn
)
100 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
105 DEBUG(DEBUG_DEBUG
, ("ibwtest_send_id\n"));
106 len
= sizeof(uint32_t)+strlen(tcx
->id
)+2;
107 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
108 DEBUG(DEBUG_ERR
, ("send_id: ibw_alloc_send_buf failed\n"));
112 /* first sizeof(uint32_t) size bytes are for length */
113 *((uint32_t *)buf
) = len
;
114 buf
[sizeof(uint32_t)] = (char)TESTOP_SEND_ID
;
115 strcpy(buf
+sizeof(uint32_t)+1, tcx
->id
);
117 if (ibw_send(conn
, buf
, key
, len
)) {
118 DEBUG(DEBUG_ERR
, ("send_id: ibw_send error\n"));
126 int ibwtest_send_test_msg(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, const char *msg
)
132 if (conn
->state
!=IBWC_CONNECTED
)
133 return 0; /* not yet up */
135 len
= strlen(msg
) + 2 + sizeof(uint32_t);
136 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
137 fprintf(stderr
, "send_test_msg: ibw_alloc_send_buf failed\n");
141 *((uint32_t *)buf
) = len
;
143 p
+= sizeof(uint32_t);
144 p
[0] = (char)TESTOP_SEND_TEXT
;
148 if (ibw_send(conn
, buf
, key
, len
)) {
149 DEBUG(DEBUG_ERR
, ("send_test_msg: ibw_send error\n"));
157 unsigned char ibwtest_fill_random(unsigned char *buf
, uint32_t size
)
160 unsigned char sum
= 0;
164 value
= (unsigned char)(256.0 * (rand() / (RAND_MAX
+ 1.0)));
171 unsigned char ibwtest_get_sum(unsigned char *buf
, uint32_t size
)
174 unsigned char sum
= 0;
183 int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, uint32_t size
)
190 len
= sizeof(uint32_t) + 1 + size
+ 1;
191 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
192 DEBUG(DEBUG_ERR
, ("varsize/ibw_alloc_send_buf failed\n"));
195 *((uint32_t *)buf
) = len
;
196 buf
[sizeof(uint32_t)] = TESTOP_SEND_RND
;
197 sum
= ibwtest_fill_random(buf
+ sizeof(uint32_t) + 1, size
);
198 buf
[sizeof(uint32_t) + 1 + size
] = sum
;
199 if (ibw_send(conn
, buf
, key
, len
)) {
200 DEBUG(DEBUG_ERR
, ("varsize/ibw_send failed\n"));
208 int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
)
213 for(i
=0; i
<tcx
->nmsg
; i
++)
215 //size = (uint32_t)((float)(tcx->maxsize) * (rand() / (RAND_MAX + 1.0)));
216 size
= (uint32_t)((float)(tcx
->maxsize
) * ((float)(i
+1)/(float)tcx
->nmsg
));
217 if (ibwtest_do_varsize_scenario_conn_size(tcx
, conn
, size
))
223 /*int ibwtest_do_varsize_scenario(ibwtest_ctx *tcx)
226 struct ibw_conn *conn;
228 for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
229 if (conn->state==IBWC_CONNECTED) {
230 rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
237 int ibwtest_connstate_handler(struct ibw_ctx
*ctx
, struct ibw_conn
*conn
)
239 struct ibwtest_ctx
*tcx
= NULL
; /* userdata */
240 struct ibwtest_conn
*tconn
= NULL
; /* userdata */
243 tcx
= talloc_get_type(ctx
->ctx_userdata
, struct ibwtest_ctx
);
247 DEBUG(DEBUG_DEBUG
, ("test IBWS_INIT\n"));
250 DEBUG(DEBUG_DEBUG
, ("test IBWS_READY\n"));
252 case IBWS_CONNECT_REQUEST
:
253 DEBUG(DEBUG_DEBUG
, ("test IBWS_CONNECT_REQUEST\n"));
254 tconn
= talloc_zero(conn
, struct ibwtest_conn
);
255 if (ibw_accept(ctx
, conn
, tconn
)) {
256 DEBUG(DEBUG_ERR
, ("error accepting the connect request\n"));
260 DEBUG(DEBUG_DEBUG
, ("test IBWS_STOPPED\n"));
261 tcx
->kill_me
= 1; /* main loop can exit */
264 DEBUG(DEBUG_DEBUG
, ("test IBWS_ERROR\n"));
265 ibw_stop(tcx
->ibwctx
);
274 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
275 switch(conn
->state
) {
277 DEBUG(DEBUG_DEBUG
, ("test IBWC_INIT\n"));
280 if (gettimeofday(&tcx
->start_time
, NULL
)) {
281 DEBUG(DEBUG_ERR
, ("gettimeofday error %d", errno
));
284 ibwtest_send_id(conn
);
286 case IBWC_DISCONNECTED
:
287 DEBUG(DEBUG_DEBUG
, ("test IBWC_DISCONNECTED\n"));
291 DEBUG(DEBUG_DEBUG
, ("test IBWC_ERROR %s\n", ibw_getLastError()));
301 int ibwtest_receive_handler(struct ibw_conn
*conn
, void *buf
, int n
)
303 struct ibwtest_conn
*tconn
;
305 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
309 assert(n
>=sizeof(uint32_t)+1);
310 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
312 op
= (enum testopcode
)((char *)buf
)[sizeof(uint32_t)];
313 if (op
==TESTOP_SEND_ID
) {
314 tconn
->id
= talloc_strdup(tconn
, ((char *)buf
)+sizeof(uint32_t)+1);
316 if (op
==TESTOP_SEND_ID
|| op
==TESTOP_SEND_TEXT
) {
317 DEBUG(DEBUG_DEBUG
, ("[%d]msg from %s: \"%s\"(%d)\n", op
,
318 tconn
->id
? tconn
->id
: "NULL", ((char *)buf
)+sizeof(uint32_t)+1, n
));
321 if (tcx
->is_server
) {
322 if (op
==TESTOP_SEND_RND
) {
324 sum
= ibwtest_get_sum((unsigned char *)buf
+ sizeof(uint32_t) + 1,
325 n
- sizeof(uint32_t) - 2);
326 DEBUG(DEBUG_DEBUG
, ("[%d]msg varsize %u/sum %u from %s\n",
328 (uint32_t)(n
- sizeof(uint32_t) - 2),
330 tconn
->id
? tconn
->id
: "NULL"));
331 if (sum
!=((unsigned char *)buf
)[n
-1]) {
332 DEBUG(DEBUG_ERR
, ("ERROR: checksum mismatch %u!=%u\n",
333 (uint32_t)sum
, (uint32_t)((unsigned char *)buf
)[n
-1]));
334 ibw_stop(tcx
->ibwctx
);
337 } else if (op
!=TESTOP_SEND_ID
) {
341 /* bounce message regardless what it is */
342 if (ibw_alloc_send_buf(conn
, (void **)&buf2
, &key2
, n
)) {
343 fprintf(stderr
, "ibw_alloc_send_buf error #2\n");
346 memcpy(buf2
, buf
, n
);
347 if (ibw_send(conn
, buf2
, key2
, n
)) {
348 fprintf(stderr
, "ibw_send error #2\n");
353 } else { /* client: */
354 if (op
==TESTOP_SEND_ID
&& tcx
->maxsize
) {
355 /* send them in one blow */
356 rc
= ibwtest_do_varsize_scenario_conn(tcx
, conn
);
361 sprintf(msg
, "hello world %d", tcx
->nmsg
--);
362 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
364 ibw_stop(tcx
->ibwctx
);
378 void ibwtest_timeout_handler(struct event_context
*ev
, struct timed_event
*te
,
379 struct timeval t
, void *private_data
)
381 struct ibwtest_ctx
*tcx
= talloc_get_type(private_data
, struct ibwtest_ctx
);
384 if (!tcx
->is_server
) {
385 struct ibw_conn
*conn
;
388 /* fill it with something variable... */
389 sprintf(msg
, "hello world %d", tcx
->cnt
++);
391 /* send something to everybody... */
392 for(conn
=tcx
->ibwctx
->conn_list
; conn
!=NULL
; conn
=conn
->next
) {
393 if (conn
->state
==IBWC_CONNECTED
) {
394 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
399 } /* else allow main loop run */
402 static struct ibwtest_ctx
*testctx
= NULL
;
404 void ibwtest_sigint_handler(int sig
)
406 DEBUG(DEBUG_ERR
, ("got SIGINT\n"));
408 if (testctx
->ibwctx
->state
==IBWS_READY
||
409 testctx
->ibwctx
->state
==IBWS_CONNECT_REQUEST
||
410 testctx
->ibwctx
->state
==IBWS_ERROR
)
412 if (testctx
->stopping
) {
413 DEBUG(DEBUG_DEBUG
, ("forcing exit...\n"));
414 testctx
->kill_me
= 1;
416 /* mostly expected case */
417 ibw_stop(testctx
->ibwctx
);
418 testctx
->stopping
= 1;
421 testctx
->kill_me
= 1;
425 int ibwtest_parse_attrs(struct ibwtest_ctx
*tcx
, char *optext
,
426 struct ibw_initattr
**pattrs
, int *nattrs
, char op
)
429 int porcess_next
= 1;
431 struct ibw_initattr
*attrs
= NULL
;
434 for(p
= optext
; *p
!='\0'; p
++) {
439 attrs
= (struct ibw_initattr
*)talloc_size(tcx
,
440 n
* sizeof(struct ibw_initattr
));
441 for(p
= optext
; *p
!='\0'; p
++) {
446 fprintf(stderr
, "-%c format error\n", op
);
450 attrs
[i
].value
= q
+ 1;
454 p
= q
; /* ++ at end */
457 *p
= '\0'; /* ++ at end */
467 static int ibwtest_get_address(const char *address
, struct in_addr
*addr
)
469 if (inet_pton(AF_INET
, address
, addr
) <= 0) {
470 struct hostent
*he
= gethostbyname(address
);
471 if (he
== NULL
|| he
->h_length
> sizeof(*addr
)) {
472 DEBUG(DEBUG_ERR
, ("invalid nework address '%s'\n", address
));
475 memcpy(addr
, he
->h_addr
, he
->h_length
);
480 int ibwtest_getdests(struct ibwtest_ctx
*tcx
, char op
)
483 struct ibw_initattr
*attrs
= NULL
;
484 struct sockaddr_in
*p
;
487 tmp
= talloc_strdup(tcx
, optarg
);
488 if (tmp
== NULL
) return -1;
489 /* hack to reuse the above ibw_initattr parser */
490 if (ibwtest_parse_attrs(tcx
, tmp
, &attrs
, &tcx
->naddrs
, op
))
493 tcx
->addrs
= talloc_size(tcx
,
494 tcx
->naddrs
* sizeof(struct sockaddr_in
));
495 for(i
=0; i
<tcx
->naddrs
; i
++) {
497 p
->sin_family
= AF_INET
;
498 if (ibwtest_get_address(attrs
[i
].name
, &p
->sin_addr
))
500 p
->sin_port
= htons(atoi(attrs
[i
].value
));
506 int ibwtest_init_server(struct ibwtest_ctx
*tcx
)
508 if (tcx
->naddrs
!=1) {
509 fprintf(stderr
, "incorrect number of addrs(%d!=1)\n", tcx
->naddrs
);
513 if (ibw_bind(tcx
->ibwctx
, &tcx
->addrs
[0])) {
514 DEBUG(DEBUG_ERR
, ("ERROR: ibw_bind failed\n"));
518 if (ibw_listen(tcx
->ibwctx
, 1)) {
519 DEBUG(DEBUG_ERR
, ("ERROR: ibw_listen failed\n"));
523 /* continued at IBWS_READY */
527 void ibwtest_usage(struct ibwtest_ctx
*tcx
, char *name
)
530 printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name
);
531 printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
532 printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
533 printf("\t-a addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
534 printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx
->nsec
);
535 printf("\t\t send message periodically and endless when nsec is non-zero\n");
536 printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
537 printf("\t-n number of messages to send [default %d]\n", tcx
->nmsg
);
538 printf("\t-l usec time to sleep in the main loop [default %d]\n", tcx
->sleep_usec
);
539 printf("\t-v max variable msg size in bytes [default %d], 0=don't send var. size\n", tcx
->maxsize
);
540 printf("\t-d LogLevel [default %d]\n", DEBUGLEVEL
);
541 printf("Press ctrl+C to stop the program.\n");
544 int main(int argc
, char *argv
[])
548 struct tevent_context
*ev
= NULL
;
549 struct ibwtest_ctx
*tcx
= NULL
;
552 tcx
= talloc_zero(NULL
, struct ibwtest_ctx
);
553 memset(tcx
, 0, sizeof(struct ibwtest_ctx
));
558 /* here is the only case we can't avoid using global... */
560 signal(SIGINT
, ibwtest_sigint_handler
);
561 srand((unsigned)time(NULL
));
563 while ((op
=getopt(argc
, argv
, "i:o:d:m:st:n:l:v:a:")) != -1) {
566 tcx
->id
= talloc_strdup(tcx
, optarg
);
569 tcx
->opts
= talloc_strdup(tcx
, optarg
);
570 if (tcx
->opts
) goto cleanup
;
571 if (ibwtest_parse_attrs(tcx
, tcx
->opts
, &tcx
->attrs
,
576 if (ibwtest_getdests(tcx
, op
))
583 tcx
->nsec
= (unsigned int)atoi(optarg
);
586 tcx
->nmsg
= atoi(optarg
);
589 tcx
->sleep_usec
= (unsigned int)atoi(optarg
);
592 tcx
->maxsize
= (unsigned int)atoi(optarg
);
595 DEBUGLEVEL
= atoi(optarg
);
598 fprintf(stderr
, "ERROR: unknown option -%c\n", (char)op
);
599 ibwtest_usage(tcx
, argv
[0]);
604 ibwtest_usage(tcx
, argv
[0]);
608 ev
= event_context_init(NULL
);
611 tcx
->ibwctx
= ibw_init(tcx
->attrs
, tcx
->nattrs
,
613 ibwtest_connstate_handler
,
614 ibwtest_receive_handler
,
621 rc
= ibwtest_init_server(tcx
);
623 rc
= ibwtest_connect_everybody(tcx
);
627 while(!tcx
->kill_me
&& !tcx
->error
) {
629 event_add_timed(ev
, tcx
, timeval_current_ofs(0, tcx
->nsec
),
630 ibwtest_timeout_handler
, tcx
);
636 usleep(tcx
->sleep_usec
);
639 if (!tcx
->is_server
&& tcx
->nsent
!=0 && !tcx
->error
) {
640 if (gettimeofday(&tcx
->end_time
, NULL
)) {
641 DEBUG(DEBUG_ERR
, ("gettimeofday error %d\n", errno
));
644 usec
= (tcx
->end_time
.tv_sec
- tcx
->start_time
.tv_sec
) * 1000000 +
645 (tcx
->end_time
.tv_usec
- tcx
->start_time
.tv_usec
);
646 printf("usec: %f, nmsg: %d, usec/nmsg: %f\n",
647 usec
, tcx
->nsent
, usec
/(float)tcx
->nsent
);
651 result
= 0; /* everything OK */
658 DEBUG(DEBUG_ERR
, ("exited with code %d\n", result
));