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/>.
24 #include "system/network.h"
25 #include "system/time.h"
26 #include "system/wait.h"
32 #include "lib/util/time.h"
33 #include "lib/util/debug.h"
35 #include "common/logging.h"
37 #include "ib/ibwrapper.h"
43 struct ibw_initattr
*attrs
;
45 char *opts
; /* option string */
47 struct sockaddr_in
*addrs
; /* dynamic array of dest addrs */
50 unsigned int nsec
; /* delta times between messages in nanosec */
51 unsigned int sleep_usec
; /* microsecs to sleep in the main loop to emulate overloading */
52 uint32_t maxsize
; /* maximum variable message size */
57 int nmsg
; /* number of messages to send (client) */
62 struct ibw_ctx
*ibwctx
;
64 struct timeval start_time
, end_time
;
77 static int ibwtest_connect_everybody(struct ibwtest_ctx
*tcx
)
79 struct ibw_conn
*conn
;
80 struct ibwtest_conn
*tconn
= talloc_zero(tcx
, struct ibwtest_conn
);
83 for(i
=0; i
<tcx
->naddrs
; i
++) {
84 conn
= ibw_conn_new(tcx
->ibwctx
, tconn
);
85 if (ibw_connect(conn
, &tcx
->addrs
[i
], tconn
)) {
86 fprintf(stderr
, "ibw_connect error at %d\n", i
);
90 DEBUG(DEBUG_DEBUG
, ("sent %d connect request...\n", tcx
->naddrs
));
95 static int ibwtest_send_id(struct ibw_conn
*conn
)
97 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
102 DEBUG(DEBUG_DEBUG
, ("ibwtest_send_id\n"));
103 len
= sizeof(uint32_t)+strlen(tcx
->id
)+2;
104 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
105 DEBUG(DEBUG_ERR
, ("send_id: ibw_alloc_send_buf failed\n"));
109 /* first sizeof(uint32_t) size bytes are for length */
110 *((uint32_t *)buf
) = len
;
111 buf
[sizeof(uint32_t)] = (char)TESTOP_SEND_ID
;
112 strcpy(buf
+sizeof(uint32_t)+1, tcx
->id
);
114 if (ibw_send(conn
, buf
, key
, len
)) {
115 DEBUG(DEBUG_ERR
, ("send_id: ibw_send error\n"));
123 static int ibwtest_send_test_msg(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, const char *msg
)
129 if (conn
->state
!=IBWC_CONNECTED
)
130 return 0; /* not yet up */
132 len
= strlen(msg
) + 2 + sizeof(uint32_t);
133 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
134 fprintf(stderr
, "send_test_msg: ibw_alloc_send_buf failed\n");
138 *((uint32_t *)buf
) = len
;
140 p
+= sizeof(uint32_t);
141 p
[0] = (char)TESTOP_SEND_TEXT
;
145 if (ibw_send(conn
, buf
, key
, len
)) {
146 DEBUG(DEBUG_ERR
, ("send_test_msg: ibw_send error\n"));
154 static unsigned char ibwtest_fill_random(unsigned char *buf
, uint32_t size
)
157 unsigned char sum
= 0;
161 value
= (unsigned char)(256.0 * (rand() / (RAND_MAX
+ 1.0)));
168 static unsigned char ibwtest_get_sum(unsigned char *buf
, uint32_t size
)
171 unsigned char sum
= 0;
180 static int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
, uint32_t size
)
187 len
= sizeof(uint32_t) + 1 + size
+ 1;
188 if (ibw_alloc_send_buf(conn
, (void **)&buf
, &key
, len
)) {
189 DEBUG(DEBUG_ERR
, ("varsize/ibw_alloc_send_buf failed\n"));
192 *((uint32_t *)buf
) = len
;
193 buf
[sizeof(uint32_t)] = TESTOP_SEND_RND
;
194 sum
= ibwtest_fill_random(buf
+ sizeof(uint32_t) + 1, size
);
195 buf
[sizeof(uint32_t) + 1 + size
] = sum
;
196 if (ibw_send(conn
, buf
, key
, len
)) {
197 DEBUG(DEBUG_ERR
, ("varsize/ibw_send failed\n"));
205 static int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx
*tcx
, struct ibw_conn
*conn
)
210 for(i
=0; i
<tcx
->nmsg
; i
++)
212 //size = (uint32_t)((float)(tcx->maxsize) * (rand() / (RAND_MAX + 1.0)));
213 size
= (uint32_t)((float)(tcx
->maxsize
) * ((float)(i
+1)/(float)tcx
->nmsg
));
214 if (ibwtest_do_varsize_scenario_conn_size(tcx
, conn
, size
))
220 /*int ibwtest_do_varsize_scenario(ibwtest_ctx *tcx)
223 struct ibw_conn *conn;
225 for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
226 if (conn->state==IBWC_CONNECTED) {
227 rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
234 static int ibwtest_connstate_handler(struct ibw_ctx
*ctx
, struct ibw_conn
*conn
)
236 struct ibwtest_ctx
*tcx
= NULL
; /* userdata */
237 struct ibwtest_conn
*tconn
= NULL
; /* userdata */
240 tcx
= talloc_get_type(ctx
->ctx_userdata
, struct ibwtest_ctx
);
244 DEBUG(DEBUG_DEBUG
, ("test IBWS_INIT\n"));
247 DEBUG(DEBUG_DEBUG
, ("test IBWS_READY\n"));
249 case IBWS_CONNECT_REQUEST
:
250 DEBUG(DEBUG_DEBUG
, ("test IBWS_CONNECT_REQUEST\n"));
251 tconn
= talloc_zero(conn
, struct ibwtest_conn
);
252 if (ibw_accept(ctx
, conn
, tconn
)) {
253 DEBUG(DEBUG_ERR
, ("error accepting the connect request\n"));
257 DEBUG(DEBUG_DEBUG
, ("test IBWS_STOPPED\n"));
258 tcx
->kill_me
= 1; /* main loop can exit */
261 DEBUG(DEBUG_DEBUG
, ("test IBWS_ERROR\n"));
262 ibw_stop(tcx
->ibwctx
);
271 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
272 switch(conn
->state
) {
274 DEBUG(DEBUG_DEBUG
, ("test IBWC_INIT\n"));
277 if (gettimeofday(&tcx
->start_time
, NULL
)) {
278 DEBUG(DEBUG_ERR
, ("gettimeofday error %d", errno
));
281 ibwtest_send_id(conn
);
283 case IBWC_DISCONNECTED
:
284 DEBUG(DEBUG_DEBUG
, ("test IBWC_DISCONNECTED\n"));
288 DEBUG(DEBUG_DEBUG
, ("test IBWC_ERROR %s\n", ibw_getLastError()));
298 static int ibwtest_receive_handler(struct ibw_conn
*conn
, void *buf
, int n
)
300 struct ibwtest_conn
*tconn
;
302 struct ibwtest_ctx
*tcx
= talloc_get_type(conn
->ctx
->ctx_userdata
, struct ibwtest_ctx
);
306 assert(n
>=sizeof(uint32_t)+1);
307 tconn
= talloc_get_type(conn
->conn_userdata
, struct ibwtest_conn
);
309 op
= (enum testopcode
)((char *)buf
)[sizeof(uint32_t)];
310 if (op
==TESTOP_SEND_ID
) {
311 tconn
->id
= talloc_strdup(tconn
, ((char *)buf
)+sizeof(uint32_t)+1);
313 if (op
==TESTOP_SEND_ID
|| op
==TESTOP_SEND_TEXT
) {
314 DEBUG(DEBUG_DEBUG
, ("[%d]msg from %s: \"%s\"(%d)\n", op
,
315 tconn
->id
? tconn
->id
: "NULL", ((char *)buf
)+sizeof(uint32_t)+1, n
));
318 if (tcx
->is_server
) {
319 if (op
==TESTOP_SEND_RND
) {
321 sum
= ibwtest_get_sum((unsigned char *)buf
+ sizeof(uint32_t) + 1,
322 n
- sizeof(uint32_t) - 2);
323 DEBUG(DEBUG_DEBUG
, ("[%d]msg varsize %u/sum %u from %s\n",
325 (uint32_t)(n
- sizeof(uint32_t) - 2),
327 tconn
->id
? tconn
->id
: "NULL"));
328 if (sum
!=((unsigned char *)buf
)[n
-1]) {
329 DEBUG(DEBUG_ERR
, ("ERROR: checksum mismatch %u!=%u\n",
330 (uint32_t)sum
, (uint32_t)((unsigned char *)buf
)[n
-1]));
331 ibw_stop(tcx
->ibwctx
);
334 } else if (op
!=TESTOP_SEND_ID
) {
338 /* bounce message regardless what it is */
339 if (ibw_alloc_send_buf(conn
, (void **)&buf2
, &key2
, n
)) {
340 fprintf(stderr
, "ibw_alloc_send_buf error #2\n");
343 memcpy(buf2
, buf
, n
);
344 if (ibw_send(conn
, buf2
, key2
, n
)) {
345 fprintf(stderr
, "ibw_send error #2\n");
350 } else { /* client: */
351 if (op
==TESTOP_SEND_ID
&& tcx
->maxsize
) {
352 /* send them in one blow */
353 rc
= ibwtest_do_varsize_scenario_conn(tcx
, conn
);
358 sprintf(msg
, "hello world %d", tcx
->nmsg
--);
359 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
361 ibw_stop(tcx
->ibwctx
);
375 static void ibwtest_timeout_handler(struct tevent_context
*ev
,
376 struct tevent_timer
*te
,
377 struct timeval t
, void *private_data
)
379 struct ibwtest_ctx
*tcx
= talloc_get_type(private_data
, struct ibwtest_ctx
);
382 if (!tcx
->is_server
) {
383 struct ibw_conn
*conn
;
386 /* fill it with something variable... */
387 sprintf(msg
, "hello world %d", tcx
->cnt
++);
389 /* send something to everybody... */
390 for(conn
=tcx
->ibwctx
->conn_list
; conn
!=NULL
; conn
=conn
->next
) {
391 if (conn
->state
==IBWC_CONNECTED
) {
392 rc
= ibwtest_send_test_msg(tcx
, conn
, msg
);
397 } /* else allow main loop run */
400 static struct ibwtest_ctx
*testctx
= NULL
;
402 static void ibwtest_sigint_handler(int sig
)
404 DEBUG(DEBUG_ERR
, ("got SIGINT\n"));
406 if (testctx
->ibwctx
->state
==IBWS_READY
||
407 testctx
->ibwctx
->state
==IBWS_CONNECT_REQUEST
||
408 testctx
->ibwctx
->state
==IBWS_ERROR
)
410 if (testctx
->stopping
) {
411 DEBUG(DEBUG_DEBUG
, ("forcing exit...\n"));
412 testctx
->kill_me
= 1;
414 /* mostly expected case */
415 ibw_stop(testctx
->ibwctx
);
416 testctx
->stopping
= 1;
419 testctx
->kill_me
= 1;
423 static int ibwtest_parse_attrs(struct ibwtest_ctx
*tcx
, char *optext
,
424 struct ibw_initattr
**pattrs
, int *nattrs
, char op
)
427 int porcess_next
= 1;
429 struct ibw_initattr
*attrs
= NULL
;
432 for(p
= optext
; *p
!='\0'; p
++) {
437 attrs
= (struct ibw_initattr
*)talloc_size(tcx
,
438 n
* sizeof(struct ibw_initattr
));
439 for(p
= optext
; *p
!='\0'; p
++) {
444 fprintf(stderr
, "-%c format error\n", op
);
448 attrs
[i
].value
= q
+ 1;
452 p
= q
; /* ++ at end */
455 *p
= '\0'; /* ++ at end */
465 static int ibwtest_get_address(const char *address
, struct in_addr
*addr
)
467 if (inet_pton(AF_INET
, address
, addr
) <= 0) {
468 struct hostent
*he
= gethostbyname(address
);
469 if (he
== NULL
|| he
->h_length
> sizeof(*addr
)) {
470 DEBUG(DEBUG_ERR
, ("invalid nework address '%s'\n", address
));
473 memcpy(addr
, he
->h_addr
, he
->h_length
);
478 static int ibwtest_getdests(struct ibwtest_ctx
*tcx
, char op
)
481 struct ibw_initattr
*attrs
= NULL
;
482 struct sockaddr_in
*p
;
485 tmp
= talloc_strdup(tcx
, optarg
);
486 if (tmp
== NULL
) return -1;
487 /* hack to reuse the above ibw_initattr parser */
488 if (ibwtest_parse_attrs(tcx
, tmp
, &attrs
, &tcx
->naddrs
, op
))
491 tcx
->addrs
= talloc_size(tcx
,
492 tcx
->naddrs
* sizeof(struct sockaddr_in
));
493 for(i
=0; i
<tcx
->naddrs
; i
++) {
495 p
->sin_family
= AF_INET
;
496 if (ibwtest_get_address(attrs
[i
].name
, &p
->sin_addr
))
498 p
->sin_port
= htons(atoi(attrs
[i
].value
));
504 static int ibwtest_init_server(struct ibwtest_ctx
*tcx
)
506 if (tcx
->naddrs
!=1) {
507 fprintf(stderr
, "incorrect number of addrs(%d!=1)\n", tcx
->naddrs
);
511 if (ibw_bind(tcx
->ibwctx
, &tcx
->addrs
[0])) {
512 DEBUG(DEBUG_ERR
, ("ERROR: ibw_bind failed\n"));
516 if (ibw_listen(tcx
->ibwctx
, 1)) {
517 DEBUG(DEBUG_ERR
, ("ERROR: ibw_listen failed\n"));
521 /* continued at IBWS_READY */
525 static void ibwtest_usage(struct ibwtest_ctx
*tcx
, char *name
)
528 printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name
);
529 printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
530 printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
531 printf("\t-a addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
532 printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx
->nsec
);
533 printf("\t\t send message periodically and endless when nsec is non-zero\n");
534 printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
535 printf("\t-n number of messages to send [default %d]\n", tcx
->nmsg
);
536 printf("\t-l usec time to sleep in the main loop [default %d]\n", tcx
->sleep_usec
);
537 printf("\t-v max variable msg size in bytes [default %d], 0=don't send var. size\n", tcx
->maxsize
);
538 printf("\t-d LogLevel [default %d]\n", DEBUGLEVEL
);
539 printf("Press ctrl+C to stop the program.\n");
542 int main(int argc
, char *argv
[])
546 struct tevent_context
*ev
= NULL
;
547 struct ibwtest_ctx
*tcx
= NULL
;
550 tcx
= talloc_zero(NULL
, struct ibwtest_ctx
);
551 memset(tcx
, 0, sizeof(struct ibwtest_ctx
));
556 /* here is the only case we can't avoid using global... */
558 signal(SIGINT
, ibwtest_sigint_handler
);
559 srand((unsigned)time(NULL
));
561 while ((op
=getopt(argc
, argv
, "i:o:d:m:st:n:l:v:a:")) != -1) {
564 tcx
->id
= talloc_strdup(tcx
, optarg
);
567 tcx
->opts
= talloc_strdup(tcx
, optarg
);
568 if (tcx
->opts
) goto cleanup
;
569 if (ibwtest_parse_attrs(tcx
, tcx
->opts
, &tcx
->attrs
,
574 if (ibwtest_getdests(tcx
, op
))
581 tcx
->nsec
= (unsigned int)atoi(optarg
);
584 tcx
->nmsg
= atoi(optarg
);
587 tcx
->sleep_usec
= (unsigned int)atoi(optarg
);
590 tcx
->maxsize
= (unsigned int)atoi(optarg
);
593 DEBUGLEVEL
= atoi(optarg
);
596 fprintf(stderr
, "ERROR: unknown option -%c\n", (char)op
);
597 ibwtest_usage(tcx
, argv
[0]);
602 ibwtest_usage(tcx
, argv
[0]);
606 ev
= tevent_context_init(NULL
);
609 tcx
->ibwctx
= ibw_init(tcx
->attrs
, tcx
->nattrs
,
611 ibwtest_connstate_handler
,
612 ibwtest_receive_handler
,
619 rc
= ibwtest_init_server(tcx
);
621 rc
= ibwtest_connect_everybody(tcx
);
625 while(!tcx
->kill_me
&& !tcx
->error
) {
627 tevent_add_timer(ev
, tcx
,
628 timeval_current_ofs(0, tcx
->nsec
),
629 ibwtest_timeout_handler
, tcx
);
632 tevent_loop_once(ev
);
635 usleep(tcx
->sleep_usec
);
638 if (!tcx
->is_server
&& tcx
->nsent
!=0 && !tcx
->error
) {
639 if (gettimeofday(&tcx
->end_time
, NULL
)) {
640 DEBUG(DEBUG_ERR
, ("gettimeofday error %d\n", errno
));
643 usec
= (tcx
->end_time
.tv_sec
- tcx
->start_time
.tv_sec
) * 1000000 +
644 (tcx
->end_time
.tv_usec
- tcx
->start_time
.tv_usec
);
645 printf("usec: %f, nmsg: %d, usec/nmsg: %f\n",
646 usec
, tcx
->nsent
, usec
/(float)tcx
->nsent
);
650 result
= 0; /* everything OK */
657 DEBUG(DEBUG_ERR
, ("exited with code %d\n", result
));