1
2 /****************************************************************/
3 /* */
4 /* nettest_dlpi.c */
5 /* */
6 /* the actual test routines... */
7 /* */
8 /* send_dlpi_co_stream() perform a CO DLPI stream test */
9 /* recv_dlpi_co_stream() */
10 /* send_dlpi_co_rr() perform a CO DLPI req/res */
11 /* recv_dlpi_co_rr() */
12 /* send_dlpi_cl_stream() perform a CL DLPI stream test */
13 /* recv_dlpi_cl_stream() */
14 /* send_dlpi_cl_rr() perform a CL DLPI req/res */
15 /* recv_dlpi_cl_rr() */
16 /* */
17 /****************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #ifdef WANT_DLPI
24 char nettest_dlpi_id[]="\
25 @(#)nettest_dlpi.c (c) Copyright 1993-2012 Hewlett-Packard Co. Version 2.6.0";
26
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <malloc.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/poll.h>
38 #ifdef __osf__
39 #include <sys/dlpihdr.h>
40 #else /* __osf__ */
41 #include <sys/dlpi.h>
42 #ifdef __hpux__
43 #include <sys/dlpi_ext.h>
44 #endif /* __hpux__ */
45 #endif /* __osf__ */
46
47 #include "netlib.h"
48 #include "netsh.h"
49 #include "nettest_dlpi.h"
50
51 /* some stuff for DLPI control messages */
52 #define DLPI_DATA_SIZE 2048
53
54 unsigned long control_data[DLPI_DATA_SIZE];
55 struct strbuf control_message = {DLPI_DATA_SIZE, 0, (char *)control_data};
56
57 /* these are some variables global to all the DLPI tests. declare */
58 /* them static to make them global only to this file */
59
60 static int
61 rsw_size, /* remote send window size */
62 rrw_size, /* remote recv window size */
63 lsw_size, /* local send window size */
64 lrw_size, /* local recv window size */
65 req_size = 100, /* request size */
66 rsp_size = 200, /* response size */
67 send_size, /* how big are individual sends */
68 recv_size; /* how big are individual receives */
69
70 int
71 loc_ppa = 4, /* the ppa for the local interface, */
72 /* as shown as the NM Id in lanscan */
73 rem_ppa = 4, /* the ppa for the remote interface */
74 dlpi_sap = 84; /* which 802.2 SAP should we use? */
75
76 char loc_dlpi_device[32] = "/dev/dlpi";
77 char rem_dlpi_device[32] = "/dev/dlpi";
78
79 char dlpi_usage[] = "\n\
80 Usage: netperf [global options] -- [test options] \n\
81 \n\
82 CO/CL DLPI Test Options:\n\
83 -D dev[,dev] Set the local/remote DLPI device file name\n\
84 -h Display this text\n\
85 -M bytes Set the recv size (DLCO_STREAM, DLCL_STREAM)\n\
86 -m bytes Set the send size (DLCO_STREAM, DLCL_STREAM)\n\
87 -p loc[,rem] Set the local/remote PPA for the test\n\
88 -R bytes Set response size (DLCO_RR, DLCL_RR)\n\
89 -r bytes Set request size (DLCO_RR, DLCL_RR)\n\
90 -s sap Set the 802.2 sap for the test\n\
91 -W send[,recv] Set remote send/recv window sizes\n\
92 -w send[,recv] Set local send/recv window sizes\n\
93 \n\
94 For those options taking two parms, at least one must be specified;\n\
95 specifying one value without a comma will set both parms to that\n\
96 value, specifying a value with a leading comma will set just the second\n\
97 parm, a value with a trailing comma will set just the first. To set\n\
98 each parm to unique values, specify both and separate them with a\n\
99 comma.\n";
100
101
102
103 /* routines that used to be in src/netlib.c but this code is the only
104 code that uses them. raj 20110111 */
105
106
107 int
put_control(fd,len,pri,ack)108 put_control(fd, len, pri, ack)
109 int fd, len, pri, ack;
110 {
111 int error;
112 int flags = 0;
113 dl_error_ack_t *err_ack = (dl_error_ack_t *)control_data;
114
115 control_message.len = len;
116
117 if ((error = putmsg(fd, &control_message, 0, pri)) < 0 ) {
118 fprintf(where,"put_control: putmsg error %d\n",error);
119 fflush(where);
120 return(-1);
121 }
122 if ((error = getmsg(fd, &control_message, 0, &flags)) < 0) {
123 fprintf(where,"put_control: getsmg error %d\n",error);
124 fflush(where);
125 return(-1);
126 }
127 if (err_ack->dl_primitive != ack) {
128 fprintf(where,"put_control: acknowledgement error wanted %u got %u \n",
129 ack,err_ack->dl_primitive);
130 if (err_ack->dl_primitive == DL_ERROR_ACK) {
131 fprintf(where," dl_error_primitive: %u\n",
132 err_ack->dl_error_primitive);
133 fprintf(where," dl_errno: %u\n",
134 err_ack->dl_errno);
135 fprintf(where," dl_unix_errno %u\n",
136 err_ack->dl_unix_errno);
137 }
138 fflush(where);
139 return(-1);
140 }
141
142 return(0);
143 }
144
145 int
dl_open(char devfile[],int ppa)146 dl_open(char devfile[], int ppa)
147 {
148 int fd;
149 dl_attach_req_t *attach_req = (dl_attach_req_t *)control_data;
150
151 if ((fd = open(devfile, O_RDWR)) == -1) {
152 fprintf(where,"netperf: dl_open: open of %s failed, errno = %d\n",
153 devfile,
154 errno);
155 return(-1);
156 }
157
158 attach_req->dl_primitive = DL_ATTACH_REQ;
159 attach_req->dl_ppa = ppa;
160
161 if (put_control(fd, sizeof(dl_attach_req_t), 0, DL_OK_ACK) < 0) {
162 fprintf(where,
163 "netperf: dl_open: could not send control message, errno = %d\n",
164 errno);
165 return(-1);
166 }
167 return(fd);
168 }
169
170 int
dl_bind(int fd,int sap,int mode,char * dlsap_ptr,int * dlsap_len)171 dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len)
172 {
173 dl_bind_req_t *bind_req = (dl_bind_req_t *)control_data;
174 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)control_data;
175
176 bind_req->dl_primitive = DL_BIND_REQ;
177 bind_req->dl_sap = sap;
178 bind_req->dl_max_conind = 1;
179 bind_req->dl_service_mode = mode;
180 bind_req->dl_conn_mgmt = 0;
181 bind_req->dl_xidtest_flg = 0;
182
183 if (put_control(fd, sizeof(dl_bind_req_t), 0, DL_BIND_ACK) < 0) {
184 fprintf(where,
185 "netperf: dl_bind: could not send control message, errno = %d\n",
186 errno);
187 return(-1);
188 }
189
190 /* at this point, the control_data portion of the control message */
191 /* structure should contain a DL_BIND_ACK, which will have a full */
192 /* DLSAP in it. we want to extract this and pass it up so that */
193 /* it can be passed around. */
194 if (*dlsap_len >= bind_ack->dl_addr_length) {
195 bcopy((char *)bind_ack+bind_ack->dl_addr_offset,
196 dlsap_ptr,
197 bind_ack->dl_addr_length);
198 *dlsap_len = bind_ack->dl_addr_length;
199 return(0);
200 }
201 else {
202 return (-1);
203 }
204 }
205
206 int
dl_connect(int fd,unsigned char * remote_addr,int remote_addr_len)207 dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len)
208 {
209 dl_connect_req_t *connection_req = (dl_connect_req_t *)control_data;
210 dl_connect_con_t *connection_con = (dl_connect_con_t *)control_data;
211 struct pollfd pinfo;
212
213 int flags = 0;
214
215 /* this is here on the off chance that we really want some data */
216 u_long data_area[512];
217 struct strbuf data_message;
218
219 int error;
220
221 data_message.maxlen = 2048;
222 data_message.len = 0;
223 data_message.buf = (char *)data_area;
224
225 connection_req->dl_primitive = DL_CONNECT_REQ;
226 connection_req->dl_dest_addr_length = remote_addr_len;
227 connection_req->dl_dest_addr_offset = sizeof(dl_connect_req_t);
228 connection_req->dl_qos_length = 0;
229 connection_req->dl_qos_offset = 0;
230 bcopy (remote_addr,
231 (unsigned char *)control_data + sizeof(dl_connect_req_t),
232 remote_addr_len);
233
234 /* well, I would call the put_control routine here, but the sequence */
235 /* of connection stuff with DLPI is a bit screwey with all this */
236 /* message passing - Toto, I don't think were in Berkeley anymore. */
237
238 control_message.len = sizeof(dl_connect_req_t) + remote_addr_len;
239 if ((error = putmsg(fd,&control_message,0,0)) !=0) {
240 fprintf(where,"dl_connect: putmsg failure, errno = %d, error 0x%x \n",
241 errno,error);
242 fflush(where);
243 return(-1);
244 };
245
246 pinfo.fd = fd;
247 pinfo.events = POLLIN | POLLPRI;
248 pinfo.revents = 0;
249
250 if ((error = getmsg(fd,&control_message,&data_message,&flags)) != 0) {
251 fprintf(where,"dl_connect: getmsg failure, errno = %d, error 0x%x \n",
252 errno,error);
253 fflush(where);
254 return(-1);
255 }
256 while (control_data[0] == DL_TEST_CON) {
257 /* i suppose we spin until we get an error, or a connection */
258 /* indication */
259 if((error = getmsg(fd,&control_message,&data_message,&flags)) !=0) {
260 fprintf(where,"dl_connect: getmsg failure, errno = %d, error = 0x%x\n",
261 errno,error);
262 fflush(where);
263 return(-1);
264 }
265 }
266
267 /* we are out - it either worked or it didn't - which was it? */
268 if (control_data[0] == DL_CONNECT_CON) {
269 return(0);
270 }
271 else {
272 return(-1);
273 }
274 }
275
276 int
dl_accept(fd,remote_addr,remote_addr_len)277 dl_accept(fd, remote_addr, remote_addr_len)
278 int fd;
279 unsigned char *remote_addr;
280 int remote_addr_len;
281 {
282 dl_connect_ind_t *connect_ind = (dl_connect_ind_t *)control_data;
283 dl_connect_res_t *connect_res = (dl_connect_res_t *)control_data;
284 int tmp_cor;
285 int flags = 0;
286
287 /* hang around and wait for a connection request */
288 getmsg(fd,&control_message,0,&flags);
289 while (control_data[0] != DL_CONNECT_IND) {
290 getmsg(fd,&control_message,0,&flags);
291 }
292
293 /* now respond to the request. at some point, we may want to be sure */
294 /* that the connection came from the correct station address, but */
295 /* will assume that we do not have to worry about it just now. */
296
297 tmp_cor = connect_ind->dl_correlation;
298
299 connect_res->dl_primitive = DL_CONNECT_RES;
300 connect_res->dl_correlation = tmp_cor;
301 connect_res->dl_resp_token = 0;
302 connect_res->dl_qos_length = 0;
303 connect_res->dl_qos_offset = 0;
304 connect_res->dl_growth = 0;
305
306 return(put_control(fd, sizeof(dl_connect_res_t), 0, DL_OK_ACK));
307
308 }
309
310 int
dl_set_window(fd,window)311 dl_set_window(fd, window)
312 int fd, window;
313 {
314 return(0);
315 }
316
317 void
dl_stats(fd)318 dl_stats(fd)
319 int fd;
320 {
321 }
322
323 int
dl_send_disc(fd)324 dl_send_disc(fd)
325 int fd;
326 {
327 }
328
329 int
dl_recv_disc(fd)330 dl_recv_disc(fd)
331 int fd;
332 {
333 }
334
335
336 /* This routine implements the CO unidirectional data transfer test */
337 /* (a.k.a. stream) for the sockets interface. It receives its */
338 /* parameters via global variables from the shell and writes its */
339 /* output to the standard output. */
340
341
342 void
send_dlpi_co_stream()343 send_dlpi_co_stream()
344 {
345
346 char *tput_title = "\
347 Recv Send Send \n\
348 Window Window Message Elapsed \n\
349 Size Size Size Time Throughput \n\
350 frames frames bytes secs. %s/sec \n\n";
351
352 char *tput_fmt_0 =
353 "%7.2f\n";
354
355 char *tput_fmt_1 =
356 "%5d %5d %6d %-6.2f %7.2f \n";
357
358 char *cpu_title = "\
359 Recv Send Send Utilization Service Demand\n\
360 Window Window Message Elapsed Send Recv Send Recv\n\
361 Size Size Size Time Throughput local remote local remote\n\
362 frames frames bytes secs. %-8.8s/s %% %% us/KB us/KB\n\n";
363
364 char *cpu_fmt_0 =
365 "%6.3f\n";
366
367 char *cpu_fmt_1 =
368 "%5d %5d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
369
370 char *ksink_fmt = "\n\
371 Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
372 Local Remote Local Remote Xfered Per Per\n\
373 Send Recv Send Recv Send (avg) Recv (avg)\n\
374 %5d %5d %5d %5d %6.4g %6.2f %6d %6.2f %6d\n";
375
376
377 float elapsed_time;
378
379 #ifdef WANT_INTERVALS
380 int interval_count;
381 #endif /* WANT_INTERVALS */
382
383 /* what we want is to have a buffer space that is at least one */
384 /* send-size greater than our send window. this will insure that we */
385 /* are never trying to re-use a buffer that may still be in the hands */
386 /* of the transport. This buffer will be malloc'd after we have found */
387 /* the size of the local senc socket buffer. We will want to deal */
388 /* with alignment and offset concerns as well. */
389
390 struct ring_elt *send_ring;
391 char *message;
392 char *message_ptr;
393 struct strbuf send_message;
394 char dlsap[BUFSIZ];
395 int dlsap_len;
396 int *message_int_ptr;
397 int message_offset;
398 int malloc_size;
399
400 int len;
401 int nummessages;
402 int send_descriptor;
403 int bytes_remaining;
404 /* with links like fddi, one can send > 32 bits worth of bytes */
405 /* during a test... ;-) */
406 double bytes_sent;
407
408 #ifdef DIRTY
409 int i;
410 #endif /* DIRTY */
411
412 float local_cpu_utilization;
413 float local_service_demand;
414 float remote_cpu_utilization;
415 float remote_service_demand;
416 double thruput;
417
418 struct dlpi_co_stream_request_struct *dlpi_co_stream_request;
419 struct dlpi_co_stream_response_struct *dlpi_co_stream_response;
420 struct dlpi_co_stream_results_struct *dlpi_co_stream_result;
421
422 dlpi_co_stream_request =
423 (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
424 dlpi_co_stream_response =
425 (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
426 dlpi_co_stream_result =
427 (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
428
429 if ( print_headers ) {
430 fprintf(where,"DLPI CO STREAM TEST\n");
431 if (local_cpu_usage || remote_cpu_usage)
432 fprintf(where,cpu_title,format_units());
433 else
434 fprintf(where,tput_title,format_units());
435 }
436
437 /* initialize a few counters */
438
439 nummessages = 0;
440 bytes_sent = 0.0;
441 times_up = 0;
442
443 /*set up the data descriptor */
444 send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
445 if (send_descriptor < 0){
446 perror("netperf: send_dlpi_co_stream: dlpi stream data descriptor");
447 exit(1);
448 }
449
450 /* bind the puppy and get the assigned dlsap */
451 dlsap_len = BUFSIZ;
452 if (dl_bind(send_descriptor,
453 dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
454 fprintf(where,"send_dlpi_co_rr: bind failure\n");
455 fflush(where);
456 exit(1);
457 }
458
459 if (debug) {
460 fprintf(where,"send_dlpi_co_stream: send_descriptor obtained...\n");
461 }
462
463 #ifdef DL_HP_SET_LOCAL_WIN_REQ
464 if (lsw_size > 0) {
465 if (debug > 1) {
466 fprintf(where,"netperf: send_dlpi_co_stream: window send size altered from system default...\n");
467 fprintf(where," send: %d\n",lsw_size);
468 }
469 }
470 if (lrw_size > 0) {
471 if (debug > 1) {
472 fprintf(where,
473 "netperf: send_dlpi_co_stream: window recv size altered from system default...\n");
474 fprintf(where," recv: %d\n",lrw_size);
475 }
476 }
477
478
479 /* Now, we will find-out what the size actually became, and report */
480 /* that back to the user. If the call fails, we will just report a -1 */
481 /* back to the initiator for the recv buffer size. */
482
483
484 if (debug) {
485 fprintf(where,
486 "netperf: send_dlpi_co_stream: window sizes determined...\n");
487 fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size);
488 fflush(where);
489 }
490
491 #else /* DL_HP_SET_LOCAL_WIN_REQ */
492
493 lsw_size = -1;
494 lrw_size = -1;
495
496 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
497
498 /* we should pick a default send_size, it should not be larger than */
499 /* the min of the two interface MTU's, and should perhaps default to */
500 /* the Interface MTU, but for now, we will default it to 1024... if */
501 /* someone wants to change this, the should change the corresponding */
502 /* lines in the recv_dlpi_co_stream routine */
503
504 if (send_size == 0) {
505 send_size = 1024;
506 }
507
508 /* set-up the data buffer with the requested alignment and offset. */
509 /* After we have calculated the proper starting address, we want to */
510 /* put that back into the message variable so we go back to the */
511 /* proper place. note that this means that only the first send is */
512 /* guaranteed to be at the alignment specified by the -a parameter. I */
513 /* think that this is a little more "real-world" than what was found */
514 /* in previous versions. note also that we have allocated a quantity */
515 /* of memory that is at least one send-size greater than our socket */
516 /* buffer size. We want to be sure that there are at least two */
517 /* buffers allocated - this can be a bit of a problem when the */
518 /* send_size is bigger than the socket size, so we must check... the */
519 /* user may have wanted to explicitly set the "width" of our send */
520 /* buffers, we should respect that wish... */
521 if (send_width == 0) {
522 send_width = (lsw_size/send_size) + 1;
523 if (send_width == 1) send_width++;
524 }
525
526 send_ring = allocate_buffer_ring(send_width,
527 send_size,
528 local_send_align,
529 local_send_offset);
530
531 send_message.maxlen = send_size;
532 send_message.len = send_size;
533 send_message.buf = send_ring->buffer_ptr;
534
535 /* If the user has requested cpu utilization measurements, we must */
536 /* calibrate the cpu(s). We will perform this task within the tests */
537 /* themselves. If the user has specified the cpu rate, then */
538 /* calibrate_local_cpu will return rather quickly as it will have */
539 /* nothing to do. If local_cpu_rate is zero, then we will go through */
540 /* all the "normal" calibration stuff and return the rate back.*/
541
542 if (local_cpu_usage) {
543 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
544 }
545
546 /* Tell the remote end to do a listen. The server alters the socket */
547 /* paramters on the other side at this point, hence the reason for */
548 /* all the values being passed in the setup message. If the user did */
549 /* not specify any of the parameters, they will be passed as 0, which */
550 /* will indicate to the remote that no changes beyond the system's */
551 /* default should be used. */
552
553 netperf_request.content.request_type = DO_DLPI_CO_STREAM;
554 dlpi_co_stream_request->send_win_size = rsw_size;
555 dlpi_co_stream_request->recv_win_size = rrw_size;
556 dlpi_co_stream_request->receive_size = recv_size;
557 dlpi_co_stream_request->recv_alignment= remote_recv_align;
558 dlpi_co_stream_request->recv_offset = remote_recv_offset;
559 dlpi_co_stream_request->measure_cpu = remote_cpu_usage;
560 dlpi_co_stream_request->cpu_rate = remote_cpu_rate;
561 dlpi_co_stream_request->ppa = rem_ppa;
562 dlpi_co_stream_request->sap = dlpi_sap;
563 dlpi_co_stream_request->dev_name_len = strlen(rem_dlpi_device);
564 strcpy(dlpi_co_stream_request->dlpi_device,
565 rem_dlpi_device);
566
567 #ifdef __alpha
568
569 /* ok - even on a DEC box, strings are strings. I didn't really want */
570 /* to ntohl the words of a string. since I don't want to teach the */
571 /* send_ and recv_ _request and _response routines about the types, */
572 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
573 /* solution would be to use XDR, but I am still leary of being able */
574 /* to find XDR libs on all platforms I want running netperf. raj */
575 {
576 int *charword;
577 int *initword;
578 int *lastword;
579
580 initword = (int *) dlpi_co_stream_request->dlpi_device;
581 lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
582
583 for (charword = initword;
584 charword < lastword;
585 charword++) {
586
587 *charword = ntohl(*charword);
588 }
589 }
590 #endif /* __alpha */
591
592 if (test_time) {
593 dlpi_co_stream_request->test_length = test_time;
594 }
595 else {
596 dlpi_co_stream_request->test_length = test_bytes;
597 }
598 #ifdef DIRTY
599 dlpi_co_stream_request->dirty_count = rem_dirty_count;
600 dlpi_co_stream_request->clean_count = rem_clean_count;
601 #endif /* DIRTY */
602
603
604 if (debug > 1) {
605 fprintf(where,
606 "netperf: send_dlpi_co_stream: requesting DLPI CO stream test\n");
607 }
608
609 send_request();
610
611 /* The response from the remote will contain all of the relevant */
612 /* parameters for this test type. We will put them back into */
613 /* the variables here so they can be displayed if desired. The */
614 /* remote will have calibrated CPU if necessary, and will have done */
615 /* all the needed set-up we will have calibrated the cpu locally */
616 /* before sending the request, and will grab the counter value right */
617 /* after the connect returns. The remote will grab the counter right */
618 /* after the accept call. This saves the hassle of extra messages */
619 /* being sent for the TCP tests. */
620
621 recv_response();
622
623 if (!netperf_response.content.serv_errno) {
624 if (debug)
625 fprintf(where,"remote listen done.\n");
626 rrw_size = dlpi_co_stream_response->recv_win_size;
627 rsw_size = dlpi_co_stream_response->send_win_size;
628 remote_cpu_usage= dlpi_co_stream_response->measure_cpu;
629 remote_cpu_rate = dlpi_co_stream_response->cpu_rate;
630 }
631 else {
632 Set_errno(netperf_response.content.serv_errno);
633 perror("netperf: remote error");
634 exit(1);
635 }
636
637 /* Connect up to the remote port on the data descriptor */
638 if(dl_connect(send_descriptor,
639 dlpi_co_stream_response->station_addr,
640 dlpi_co_stream_response->station_addr_len) != 0) {
641 fprintf(where,"recv_dlpi_co_stream: connect failure\n");
642 fflush(where);
643 exit(1);
644 }
645
646 /* Data Socket set-up is finished. If there were problems, either the */
647 /* connect would have failed, or the previous response would have */
648 /* indicated a problem. I failed to see the value of the extra */
649 /* message after the accept on the remote. If it failed, we'll see it */
650 /* here. If it didn't, we might as well start pumping data. */
651
652 /* Set-up the test end conditions. For a stream test, they can be */
653 /* either time or byte-count based. */
654
655 if (test_time) {
656 /* The user wanted to end the test after a period of time. */
657 times_up = 0;
658 bytes_remaining = 0;
659 start_timer(test_time);
660 }
661 else {
662 /* The tester wanted to send a number of bytes. */
663 bytes_remaining = test_bytes;
664 times_up = 1;
665 }
666
667 /* The cpu_start routine will grab the current time and possibly */
668 /* value of the idle counter for later use in measuring cpu */
669 /* utilization and/or service demand and thruput. */
670
671 cpu_start(local_cpu_usage);
672
673 /* We use an "OR" to control test execution. When the test is */
674 /* controlled by time, the byte count check will always return false. */
675 /* When the test is controlled by byte count, the time test will */
676 /* always return false. When the test is finished, the whole */
677 /* expression will go false and we will stop sending data. */
678
679 #ifdef DIRTY
680 /* initialize the random number generator for putting dirty stuff */
681 /* into the send buffer. raj */
682 srand((int) getpid());
683 #endif /* DIRTY */
684
685 while ((!times_up) || (bytes_remaining > 0)) {
686
687 #ifdef DIRTY
688 /* we want to dirty some number of consecutive integers in the buffer */
689 /* we are about to send. we may also want to bring some number of */
690 /* them cleanly into the cache. The clean ones will follow any dirty */
691 /* ones into the cache. */
692 message_int_ptr = (int *)message_ptr;
693 for (i = 0; i < loc_dirty_count; i++) {
694 *message_int_ptr = rand();
695 message_int_ptr++;
696 }
697 for (i = 0; i < loc_clean_count; i++) {
698 loc_dirty_count = *message_int_ptr;
699 message_int_ptr++;
700 }
701 #endif /* DIRTY */
702
703 if((putmsg(send_descriptor,
704 0,
705 &send_message,
706 0)) != 0) {
707 if (errno == EINTR)
708 break;
709 perror("netperf: data send error");
710 exit(1);
711 }
712 send_ring = send_ring->next;
713 send_message.buf = send_ring->buffer_ptr;
714 #ifdef WANT_INTERVALS
715 for (interval_count = 0;
716 interval_count < interval_wate;
717 interval_count++);
718 #endif /* WANT_INTERVALS */
719
720 if (debug > 4) {
721 fprintf(where,"netperf: send_clpi_co_stream: putmsg called ");
722 fprintf(where,"len is %d\n",send_message.len);
723 fflush(where);
724 }
725
726 nummessages++;
727 if (bytes_remaining) {
728 bytes_remaining -= send_size;
729 }
730 }
731
732 /* The test is over. Flush the buffers to the remote end. We do a */
733 /* graceful release to insure that all data has been taken by the */
734 /* remote. this needs a little work - there is no three-way */
735 /* handshake with type two as there is with TCP, so there really */
736 /* should be a message exchange here. however, we will finesse it by */
737 /* saying that the tests shoudl run for a while. */
738
739 if (debug) {
740 fprintf(where,"sending test end signal \n");
741 fflush(where);
742 }
743
744 send_message.len = (send_size - 1);
745 if (send_message.len == 0) send_message.len = 2;
746
747 if((putmsg(send_descriptor,
748 0,
749 &send_message,
750 0)) != 0) {
751 perror("netperf: data send error");
752 exit(1);
753 }
754
755 /* this call will always give us the elapsed time for the test, and */
756 /* will also store-away the necessaries for cpu utilization */
757
758 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
759 /* how long did we really run? */
760
761 /* Get the statistics from the remote end. The remote will have */
762 /* calculated service demand and all those interesting things. If it */
763 /* wasn't supposed to care, it will return obvious values. */
764
765 recv_response();
766 if (!netperf_response.content.serv_errno) {
767 if (debug)
768 fprintf(where,"remote results obtained\n");
769 }
770 else {
771 Set_errno(netperf_response.content.serv_errno);
772 perror("netperf: remote error");
773
774 exit(1);
775 }
776
777 /* We now calculate what our thruput was for the test. In the future, */
778 /* we may want to include a calculation of the thruput measured by */
779 /* the remote, but it should be the case that for a TCP stream test, */
780 /* that the two numbers should be *very* close... We calculate */
781 /* bytes_sent regardless of the way the test length was controlled. */
782 /* If it was time, we needed to, and if it was by bytes, the user may */
783 /* have specified a number of bytes that wasn't a multiple of the */
784 /* send_size, so we really didn't send what he asked for ;-) */
785
786 bytes_sent = ((double) send_size * (double) nummessages) + (double) len;
787 thruput = calc_thruput(bytes_sent);
788
789 if (local_cpu_usage || remote_cpu_usage) {
790 /* We must now do a little math for service demand and cpu */
791 /* utilization for the system(s) */
792 /* Of course, some of the information might be bogus because */
793 /* there was no idle counter in the kernel(s). We need to make */
794 /* a note of this for the user's benefit...*/
795 if (local_cpu_usage) {
796 if (local_cpu_rate == 0.0) {
797 fprintf(where,
798 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
799 fprintf(where,
800 "Local CPU usage numbers based on process information only!\n");
801 fflush(where);
802 }
803 local_cpu_utilization = calc_cpu_util(0.0);
804 local_service_demand = calc_service_demand(bytes_sent,
805 0.0,
806 0.0,
807 0);
808 }
809 else {
810 local_cpu_utilization = -1.0;
811 local_service_demand = -1.0;
812 }
813
814 if (remote_cpu_usage) {
815 if (remote_cpu_rate == 0.0) {
816 fprintf(where,
817 "DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
818 fprintf(where,
819 "Remote CPU usage numbers based on process information only!\n");
820 fflush(where);
821 }
822 remote_cpu_utilization = dlpi_co_stream_result->cpu_util;
823 remote_service_demand = calc_service_demand(bytes_sent,
824 0.0,
825 remote_cpu_utilization,
826 dlpi_co_stream_result->num_cpus);
827 }
828 else {
829 remote_cpu_utilization = -1.0;
830 remote_service_demand = -1.0;
831 }
832
833 /* We are now ready to print all the information. If the user */
834 /* has specified zero-level verbosity, we will just print the */
835 /* local service demand, or the remote service demand. If the */
836 /* user has requested verbosity level 1, he will get the basic */
837 /* "streamperf" numbers. If the user has specified a verbosity */
838 /* of greater than 1, we will display a veritable plethora of */
839 /* background information from outside of this block as it it */
840 /* not cpu_measurement specific... */
841
842 switch (verbosity) {
843 case 0:
844 if (local_cpu_usage) {
845 fprintf(where,
846 cpu_fmt_0,
847 local_service_demand);
848 }
849 else {
850 fprintf(where,
851 cpu_fmt_0,
852 remote_service_demand);
853 }
854 break;
855 case 1:
856 case 2:
857 fprintf(where,
858 cpu_fmt_1, /* the format string */
859 rrw_size, /* remote recvbuf size */
860 lsw_size, /* local sendbuf size */
861 send_size, /* how large were the sends */
862 elapsed_time, /* how long was the test */
863 thruput, /* what was the xfer rate */
864 local_cpu_utilization, /* local cpu */
865 remote_cpu_utilization, /* remote cpu */
866 local_service_demand, /* local service demand */
867 remote_service_demand); /* remote service demand */
868 break;
869 }
870 }
871 else {
872 /* The tester did not wish to measure service demand. */
873 switch (verbosity) {
874 case 0:
875 fprintf(where,
876 tput_fmt_0,
877 thruput);
878 break;
879 case 1:
880 case 2:
881 fprintf(where,
882 tput_fmt_1, /* the format string */
883 rrw_size, /* remote recvbuf size */
884 lsw_size, /* local sendbuf size */
885 send_size, /* how large were the sends */
886 elapsed_time, /* how long did it take */
887 thruput);/* how fast did it go */
888 break;
889 }
890 }
891
892 /* it would be a good thing to include information about some of the */
893 /* other parameters that may have been set for this test, but at the */
894 /* moment, I do not wish to figure-out all the formatting, so I will */
895 /* just put this comment here to help remind me that it is something */
896 /* that should be done at a later time. */
897
898 if (verbosity > 1) {
899 /* The user wanted to know it all, so we will give it to him. */
900 /* This information will include as much as we can find about */
901 /* TCP statistics, the alignments of the sends and receives */
902 /* and all that sort of rot... */
903
904 fprintf(where,
905 ksink_fmt,
906 "Bytes",
907 "Bytes",
908 "Bytes",
909 local_send_align,
910 remote_recv_align,
911 local_send_offset,
912 remote_recv_offset,
913 bytes_sent,
914 bytes_sent / (double)nummessages,
915 nummessages,
916 bytes_sent / (double)dlpi_co_stream_result->recv_calls,
917 dlpi_co_stream_result->recv_calls);
918 }
919
920 }
921
922
923 /* This is the server-side routine for the tcp stream test. It is */
924 /* implemented as one routine. I could break things-out somewhat, but */
925 /* didn't feel it was necessary. */
926
927 int
recv_dlpi_co_stream()928 recv_dlpi_co_stream()
929 {
930
931 int data_descriptor;
932 int flags = 0;
933 int measure_cpu;
934 int bytes_received;
935 int receive_calls;
936 float elapsed_time;
937
938 struct ring_elt *recv_ring;
939 char *message_ptr;
940 char *message;
941 int *message_int_ptr;
942 struct strbuf recv_message;
943 int dirty_count;
944 int clean_count;
945 int i;
946
947 struct dlpi_co_stream_request_struct *dlpi_co_stream_request;
948 struct dlpi_co_stream_response_struct *dlpi_co_stream_response;
949 struct dlpi_co_stream_results_struct *dlpi_co_stream_results;
950
951 dlpi_co_stream_request = (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
952 dlpi_co_stream_response = (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
953 dlpi_co_stream_results = (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
954
955 if (debug) {
956 fprintf(where,"netserver: recv_dlpi_co_stream: entered...\n");
957 fflush(where);
958 }
959
960 /* We want to set-up the listen socket with all the desired */
961 /* parameters and then let the initiator know that all is ready. If */
962 /* socket size defaults are to be used, then the initiator will have */
963 /* sent us 0's. If the socket sizes cannot be changed, then we will */
964 /* send-back what they are. If that information cannot be determined, */
965 /* then we send-back -1's for the sizes. If things go wrong for any */
966 /* reason, we will drop back ten yards and punt. */
967
968 /* If anything goes wrong, we want the remote to know about it. It */
969 /* would be best if the error that the remote reports to the user is */
970 /* the actual error we encountered, rather than some bogus unexpected */
971 /* response type message. */
972
973 netperf_response.content.response_type = DLPI_CO_STREAM_RESPONSE;
974
975 /* We now alter the message_ptr variable to be at the desired */
976 /* alignment with the desired offset. */
977
978 if (debug > 1) {
979 fprintf(where,"recv_dlpi_co_stream: requested alignment of %d\n",
980 dlpi_co_stream_request->recv_alignment);
981 fflush(where);
982 }
983
984
985 /* Grab a descriptor to listen on, and then listen on it. */
986
987 if (debug > 1) {
988 fprintf(where,"recv_dlpi_co_stream: grabbing a descriptor...\n");
989 fflush(where);
990 }
991
992
993
994 #ifdef __alpha
995
996 /* ok - even on a DEC box, strings are strings. I din't really want */
997 /* to ntohl the words of a string. since I don't want to teach the */
998 /* send_ and recv_ _request and _response routines about the types, */
999 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1000 /* solution would be to use XDR, but I am still leary of being able */
1001 /* to find XDR libs on all platforms I want running netperf. raj */
1002 {
1003 int *charword;
1004 int *initword;
1005 int *lastword;
1006
1007 initword = (int *) dlpi_co_stream_request->dlpi_device;
1008 lastword = initword + ((dlpi_co_stream_request->dev_name_len + 3) / 4);
1009
1010 for (charword = initword;
1011 charword < lastword;
1012 charword++) {
1013
1014 *charword = htonl(*charword);
1015 }
1016 }
1017 #endif /* __alpha */
1018
1019 data_descriptor = dl_open(dlpi_co_stream_request->dlpi_device,
1020 dlpi_co_stream_request->ppa);
1021 if (data_descriptor < 0) {
1022 netperf_response.content.serv_errno = errno;
1023 send_response();
1024 exit(1);
1025 }
1026
1027 /* Let's get an address assigned to this descriptor so we can tell the */
1028 /* initiator how to reach the data descriptor. There may be a desire to */
1029 /* nail this descriptor to a specific address in a multi-homed, */
1030 /* multi-connection situation, but for now, we'll ignore the issue */
1031 /* and concentrate on single connection testing. */
1032
1033 /* bind the sap and retrieve the dlsap assigned by the system */
1034 dlpi_co_stream_response->station_addr_len = 14; /* arbitrary */
1035 if (dl_bind(data_descriptor,
1036 dlpi_co_stream_request->sap,
1037 DL_CODLS,
1038 (char *)dlpi_co_stream_response->station_addr,
1039 &dlpi_co_stream_response->station_addr_len) != 0) {
1040 fprintf(where,"recv_dlpi_co_stream: bind failure\n");
1041 fflush(where);
1042 exit(1);
1043 }
1044
1045 /* The initiator may have wished-us to modify the socket buffer */
1046 /* sizes. We should give it a shot. If he didn't ask us to change the */
1047 /* sizes, we should let him know what sizes were in use at this end. */
1048 /* If none of this code is compiled-in, then we will tell the */
1049 /* initiator that we were unable to play with the socket buffer by */
1050 /* setting the size in the response to -1. */
1051
1052 #ifdef DL_HP_SET_LOCAL_WIN_REQ
1053
1054 if (dlpi_co_stream_request->recv_win_size) {
1055 }
1056 /* Now, we will find-out what the size actually became, and report */
1057 /* that back to the user. If the call fails, we will just report a -1 */
1058 /* back to the initiator for the recv buffer size. */
1059
1060 #else /* the system won't let us play with the buffers */
1061
1062 dlpi_co_stream_response->recv_win_size = -1;
1063
1064 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
1065
1066 /* what sort of sizes did we end-up with? */
1067 /* this bit of code whould default to the Interface MTU */
1068 if (dlpi_co_stream_request->receive_size == 0) {
1069 recv_size = 1024;
1070 }
1071 else {
1072 recv_size = dlpi_co_stream_request->receive_size;
1073 }
1074
1075 /* tell the other fellow what our receive size became */
1076 dlpi_co_stream_response->receive_size = recv_size;
1077
1078 /* just a little prep work for when we may have to behave like the */
1079 /* sending side... */
1080 message = (char *)malloc(recv_size * 2);
1081 if (message == NULL) {
1082 printf("malloc(%d) failed!\n", recv_size * 2);
1083 exit(1);
1084 }
1085
1086 message_ptr = ALIGN_BUFFER(message, dlpi_co_stream_request->recv_alignment, dlpi_co_stream_request->recv_offset);
1087 recv_message.maxlen = recv_size;
1088 recv_message.len = 0;
1089 recv_message.buf = message_ptr;
1090
1091 if (debug > 1) {
1092 fprintf(where,
1093 "recv_dlpi_co_stream: receive alignment and offset set...\n");
1094 fflush(where);
1095 }
1096
1097 netperf_response.content.serv_errno = 0;
1098
1099 /* But wait, there's more. If the initiator wanted cpu measurements, */
1100 /* then we must call the calibrate routine, which will return the max */
1101 /* rate back to the initiator. If the CPU was not to be measured, or */
1102 /* something went wrong with the calibration, we will return a -1 to */
1103 /* the initiator. */
1104
1105 dlpi_co_stream_response->cpu_rate = 0.0; /* assume no cpu */
1106 if (dlpi_co_stream_request->measure_cpu) {
1107 dlpi_co_stream_response->measure_cpu = 1;
1108 dlpi_co_stream_response->cpu_rate =
1109 calibrate_local_cpu(dlpi_co_stream_request->cpu_rate);
1110 }
1111
1112 send_response();
1113
1114 /* accept a connection on this file descriptor. at some point, */
1115 /* dl_accept will "do the right thing" with the last two parms, but */
1116 /* for now it ignores them, so we will pass zeros. */
1117
1118 if(dl_accept(data_descriptor, 0, 0) != 0) {
1119 fprintf(where,
1120 "recv_dlpi_co_stream: error in accept, errno %d\n",
1121 errno);
1122 fflush(where);
1123 netperf_response.content.serv_errno = errno;
1124 send_response();
1125 exit(1);
1126 }
1127
1128 if (debug) {
1129 fprintf(where,"netserver:recv_dlpi_co_stream: connection accepted\n");
1130 fflush(where);
1131 }
1132
1133 /* Now it's time to start receiving data on the connection. We will */
1134 /* first grab the apropriate counters and then start grabbing. */
1135
1136 cpu_start(dlpi_co_stream_request->measure_cpu);
1137
1138 #ifdef DIRTY
1139 /* we want to dirty some number of consecutive integers in the buffer */
1140 /* we are about to recv. we may also want to bring some number of */
1141 /* them cleanly into the cache. The clean ones will follow any dirty */
1142 /* ones into the cache. */
1143
1144 dirty_count = dlpi_co_stream_request->dirty_count;
1145 clean_count = dlpi_co_stream_request->clean_count;
1146 message_int_ptr = (int *)message_ptr;
1147 for (i = 0; i < dirty_count; i++) {
1148 *message_int_ptr = rand();
1149 message_int_ptr++;
1150 }
1151 for (i = 0; i < clean_count; i++) {
1152 dirty_count = *message_int_ptr;
1153 message_int_ptr++;
1154 }
1155 #endif /* DIRTY */
1156
1157 recv_message.len = recv_size;
1158 while (recv_message.len == recv_size) {
1159 if (getmsg(data_descriptor,
1160 0,
1161 &recv_message,
1162 &flags) != 0) {
1163 netperf_response.content.serv_errno = errno;
1164 send_response();
1165 exit(1);
1166 }
1167 bytes_received += recv_message.len;
1168 receive_calls++;
1169
1170 if (debug) {
1171 fprintf(where,
1172 "netserver:recv_dlpi_co_stream: getmsg accepted %d bytes\n",
1173 recv_message.len);
1174 fflush(where);
1175 }
1176
1177
1178 #ifdef DIRTY
1179 message_int_ptr = (int *)message_ptr;
1180 for (i = 0; i < dirty_count; i++) {
1181 *message_int_ptr = rand();
1182 message_int_ptr++;
1183 }
1184 for (i = 0; i < clean_count; i++) {
1185 dirty_count = *message_int_ptr;
1186 message_int_ptr++;
1187 }
1188 #endif /* DIRTY */
1189
1190 }
1191
1192 /* The loop now exits due to zero bytes received. */
1193 /* should perform a disconnect to signal the sender that */
1194 /* we have received all the data sent. */
1195
1196 if (close(data_descriptor) == -1) {
1197 netperf_response.content.serv_errno = errno;
1198 send_response();
1199 exit(1);
1200 }
1201
1202 cpu_stop(dlpi_co_stream_request->measure_cpu,&elapsed_time);
1203
1204 /* send the results to the sender */
1205
1206 if (debug) {
1207 fprintf(where,
1208 "recv_dlpi_co_stream: got %d bytes\n",
1209 bytes_received);
1210 fprintf(where,
1211 "recv_dlpi_co_stream: got %d recvs\n",
1212 receive_calls);
1213 fflush(where);
1214 }
1215
1216 dlpi_co_stream_results->bytes_received = bytes_received;
1217 dlpi_co_stream_results->elapsed_time = elapsed_time;
1218 dlpi_co_stream_results->recv_calls = receive_calls;
1219
1220 if (dlpi_co_stream_request->measure_cpu) {
1221 dlpi_co_stream_results->cpu_util = calc_cpu_util(0.0);
1222 };
1223
1224 if (debug > 1) {
1225 fprintf(where,
1226 "recv_dlpi_co_stream: test complete, sending results.\n");
1227 fflush(where);
1228 }
1229
1230 send_response();
1231 }
1232
1233 /*********************************/
1234
send_dlpi_co_rr(char remote_host[])1235 int send_dlpi_co_rr(char remote_host[])
1236 {
1237
1238 char *tput_title = "\
1239 Local /Remote\n\
1240 Window Size Request Resp. Elapsed Trans.\n\
1241 Send Recv Size Size Time Rate \n\
1242 frames frames bytes bytes secs. per sec \n\n";
1243
1244 char *tput_fmt_0 =
1245 "%7.2f\n";
1246
1247 char *tput_fmt_1_line_1 = "\
1248 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
1249 char *tput_fmt_1_line_2 = "\
1250 %-6d %-6d\n";
1251
1252 char *cpu_title = "\
1253 Local /Remote\n\
1254 Window Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
1255 Send Recv Size Size Time Rate local remote local remote\n\
1256 frames frames bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
1257
1258 char *cpu_fmt_0 =
1259 "%6.3f\n";
1260
1261 char *cpu_fmt_1_line_1 = "\
1262 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
1263
1264 char *cpu_fmt_1_line_2 = "\
1265 %-6d %-6d\n";
1266
1267 char *ksink_fmt = "\
1268 Alignment Offset\n\
1269 Local Remote Local Remote\n\
1270 Send Recv Send Recv\n\
1271 %5d %5d %5d %5d\n";
1272
1273
1274 int timed_out = 0;
1275 float elapsed_time;
1276 int dlsap_len;
1277 char dlsap[BUFSIZ];
1278
1279 int flags = 0;
1280 char *send_message_ptr;
1281 char *recv_message_ptr;
1282 char *temp_message_ptr;
1283 struct strbuf send_message;
1284 struct strbuf recv_message;
1285
1286 int nummessages;
1287 int send_descriptor;
1288 int trans_remaining;
1289 double bytes_xferd;
1290
1291 int rsp_bytes_left;
1292
1293 /* we assume that station adresses fit within two ints */
1294 unsigned int remote_address[1];
1295
1296 float local_cpu_utilization;
1297 float local_service_demand;
1298 float remote_cpu_utilization;
1299 float remote_service_demand;
1300 double thruput;
1301
1302 struct dlpi_co_rr_request_struct *dlpi_co_rr_request;
1303 struct dlpi_co_rr_response_struct *dlpi_co_rr_response;
1304 struct dlpi_co_rr_results_struct *dlpi_co_rr_result;
1305
1306 dlpi_co_rr_request =
1307 (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
1308 dlpi_co_rr_response =
1309 (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
1310 dlpi_co_rr_result =
1311 (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
1312
1313 /* since we are now disconnected from the code that established the */
1314 /* control socket, and since we want to be able to use different */
1315 /* protocols and such, we are passed the name of the remote host and */
1316 /* must turn that into the test specific addressing information. */
1317
1318 if ( print_headers ) {
1319 fprintf(where,"DLPI CO REQUEST/RESPONSE TEST\n");
1320 if (local_cpu_usage || remote_cpu_usage)
1321 fprintf(where,cpu_title,format_units());
1322 else
1323 fprintf(where,tput_title,format_units());
1324 }
1325
1326 /* initialize a few counters */
1327
1328 nummessages = 0;
1329 bytes_xferd = 0.0;
1330 times_up = 0;
1331
1332 /* set-up the data buffers with the requested alignment and offset */
1333 temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
1334 if (temp_message_ptr == NULL) {
1335 printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
1336 exit(1);
1337 }
1338 send_message_ptr = (char *)(( (long) temp_message_ptr +
1339 (long) local_send_align - 1) &
1340 ~((long) local_send_align - 1));
1341 send_message_ptr = send_message_ptr + local_send_offset;
1342 send_message.maxlen = req_size+MAXALIGNMENT+MAXOFFSET;
1343 send_message.len = req_size;
1344 send_message.buf = send_message_ptr;
1345
1346 temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
1347 if (temp_message_ptr == NULL) {
1348 printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
1349 exit(1);
1350 }
1351 recv_message_ptr = (char *)(( (long) temp_message_ptr +
1352 (long) local_recv_align - 1) &
1353 ~((long) local_recv_align - 1));
1354 recv_message_ptr = recv_message_ptr + local_recv_offset;
1355 recv_message.maxlen = rsp_size+MAXALIGNMENT+MAXOFFSET;
1356 recv_message.len = 0;
1357 recv_message.buf = send_message_ptr;
1358
1359 /*set up the data socket */
1360
1361 send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
1362 if (send_descriptor < 0){
1363 perror("netperf: send_dlpi_co_rr: tcp stream data descriptor");
1364 exit(1);
1365 }
1366
1367 if (debug) {
1368 fprintf(where,"send_dlpi_co_rr: send_descriptor obtained...\n");
1369 }
1370
1371 /* bind the puppy and get the assigned dlsap */
1372
1373 dlsap_len = BUFSIZ;
1374 if (dl_bind(send_descriptor,
1375 dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
1376 fprintf(where,"send_dlpi_co_rr: bind failure\n");
1377 fflush(where);
1378 exit(1);
1379 }
1380
1381 /* Modify the local socket size. The reason we alter the send buffer */
1382 /* size here rather than when the connection is made is to take care */
1383 /* of decreases in buffer size. Decreasing the window size after */
1384 /* connection establishment is a TCP no-no. Also, by setting the */
1385 /* buffer (window) size before the connection is established, we can */
1386 /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
1387 /* the minimum receive buffer size at each half of the connection. */
1388 /* This is why we are altering the receive buffer size on the sending */
1389 /* size of a unidirectional transfer. If the user has not requested */
1390 /* that the socket buffers be altered, we will try to find-out what */
1391 /* their values are. If we cannot touch the socket buffer in any way, */
1392 /* we will set the values to -1 to indicate that. */
1393
1394 #ifdef DL_HP_SET_LOCAL_WIN_REQ
1395 if (lsw_size > 0) {
1396 if (debug > 1) {
1397 fprintf(where,"netperf: send_dlpi_co_rr: socket send size altered from system default...\n");
1398 fprintf(where," send: %d\n",lsw_size);
1399 }
1400 }
1401 if (lrw_size > 0) {
1402 if (debug > 1) {
1403 fprintf(where,"netperf: send_dlpi_co_rr: socket recv size altered from system default...\n");
1404 fprintf(where," recv: %d\n",lrw_size);
1405 }
1406 }
1407
1408
1409 /* Now, we will find-out what the size actually became, and report */
1410 /* that back to the user. If the call fails, we will just report a -1 */
1411 /* back to the initiator for the recv buffer size. */
1412
1413
1414 if (debug) {
1415 fprintf(where,"netperf: send_dlpi_co_rr: socket sizes determined...\n");
1416 fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size);
1417 }
1418
1419 #else /* DL_HP_SET_LOCAL_WIN_REQ */
1420
1421 lsw_size = -1;
1422 lrw_size = -1;
1423
1424 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
1425
1426 /* If the user has requested cpu utilization measurements, we must */
1427 /* calibrate the cpu(s). We will perform this task within the tests */
1428 /* themselves. If the user has specified the cpu rate, then */
1429 /* calibrate_local_cpu will return rather quickly as it will have */
1430 /* nothing to do. If local_cpu_rate is zero, then we will go through */
1431 /* all the "normal" calibration stuff and return the rate back.*/
1432
1433 if (local_cpu_usage) {
1434 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1435 }
1436
1437 /* Tell the remote end to do a listen. The server alters the socket */
1438 /* paramters on the other side at this point, hence the reason for */
1439 /* all the values being passed in the setup message. If the user did */
1440 /* not specify any of the parameters, they will be passed as 0, which */
1441 /* will indicate to the remote that no changes beyond the system's */
1442 /* default should be used. Alignment is the exception, it will */
1443 /* default to 8, which will be no alignment alterations. */
1444
1445 netperf_request.content.request_type = DO_DLPI_CO_RR;
1446 dlpi_co_rr_request->recv_win_size = rrw_size;
1447 dlpi_co_rr_request->send_win_size = rsw_size;
1448 dlpi_co_rr_request->recv_alignment = remote_recv_align;
1449 dlpi_co_rr_request->recv_offset = remote_recv_offset;
1450 dlpi_co_rr_request->send_alignment = remote_send_align;
1451 dlpi_co_rr_request->send_offset = remote_send_offset;
1452 dlpi_co_rr_request->request_size = req_size;
1453 dlpi_co_rr_request->response_size = rsp_size;
1454 dlpi_co_rr_request->measure_cpu = remote_cpu_usage;
1455 dlpi_co_rr_request->cpu_rate = remote_cpu_rate;
1456 dlpi_co_rr_request->ppa = rem_ppa;
1457 dlpi_co_rr_request->sap = dlpi_sap;
1458 dlpi_co_rr_request->dev_name_len = strlen(rem_dlpi_device);
1459 strcpy(dlpi_co_rr_request->dlpi_device,
1460 rem_dlpi_device);
1461 #ifdef __alpha
1462
1463 /* ok - even on a DEC box, strings are strings. I din't really want */
1464 /* to ntohl the words of a string. since I don't want to teach the */
1465 /* send_ and recv_ _request and _response routines about the types, */
1466 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1467 /* solution would be to use XDR, but I am still leary of being able */
1468 /* to find XDR libs on all platforms I want running netperf. raj */
1469 {
1470 int *charword;
1471 int *initword;
1472 int *lastword;
1473
1474 initword = (int *) dlpi_co_rr_request->dlpi_device;
1475 lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
1476
1477 for (charword = initword;
1478 charword < lastword;
1479 charword++) {
1480
1481 *charword = ntohl(*charword);
1482 }
1483 }
1484 #endif /* __alpha */
1485
1486 if (test_time) {
1487 dlpi_co_rr_request->test_length = test_time;
1488 }
1489 else {
1490 dlpi_co_rr_request->test_length = test_trans * -1;
1491 }
1492
1493 if (debug > 1) {
1494 fprintf(where,"netperf: send_dlpi_co_rr: requesting TCP stream test\n");
1495 }
1496
1497 send_request();
1498
1499 /* The response from the remote will contain all of the relevant */
1500 /* socket parameters for this test type. We will put them back into */
1501 /* the variables here so they can be displayed if desired. The */
1502 /* remote will have calibrated CPU if necessary, and will have done */
1503 /* all the needed set-up we will have calibrated the cpu locally */
1504 /* before sending the request, and will grab the counter value right */
1505 /* after the connect returns. The remote will grab the counter right */
1506 /* after the accept call. This saves the hassle of extra messages */
1507 /* being sent for the TCP tests. */
1508
1509 recv_response();
1510
1511 if (!netperf_response.content.serv_errno) {
1512 if (debug)
1513 fprintf(where,"remote listen done.\n");
1514 rrw_size = dlpi_co_rr_response->recv_win_size;
1515 rsw_size = dlpi_co_rr_response->send_win_size;
1516 remote_cpu_usage= dlpi_co_rr_response->measure_cpu;
1517 remote_cpu_rate = dlpi_co_rr_response->cpu_rate;
1518
1519 }
1520 else {
1521 Set_errno(netperf_response.content.serv_errno);
1522 perror("netperf: remote error");
1523
1524 exit(1);
1525 }
1526
1527 /*Connect up to the remote port on the data descriptor */
1528
1529 if(dl_connect(send_descriptor,
1530 dlpi_co_rr_response->station_addr,
1531 dlpi_co_rr_response->station_addr_len) != 0) {
1532 fprintf(where,"send_dlpi_co_rr: connect failure\n");
1533 fflush(where);
1534 exit(1);
1535 }
1536
1537 /* Data Socket set-up is finished. If there were problems, either the */
1538 /* connect would have failed, or the previous response would have */
1539 /* indicated a problem. I failed to see the value of the extra */
1540 /* message after the accept on the remote. If it failed, we'll see it */
1541 /* here. If it didn't, we might as well start pumping data. */
1542
1543 /* Set-up the test end conditions. For a request/response test, they */
1544 /* can be either time or transaction based. */
1545
1546 if (test_time) {
1547 /* The user wanted to end the test after a period of time. */
1548 times_up = 0;
1549 trans_remaining = 0;
1550 start_timer(test_time);
1551 }
1552 else {
1553 /* The tester wanted to send a number of bytes. */
1554 trans_remaining = test_bytes;
1555 times_up = 1;
1556 }
1557
1558 /* The cpu_start routine will grab the current time and possibly */
1559 /* value of the idle counter for later use in measuring cpu */
1560 /* utilization and/or service demand and thruput. */
1561
1562 cpu_start(local_cpu_usage);
1563
1564 /* We use an "OR" to control test execution. When the test is */
1565 /* controlled by time, the byte count check will always return false. */
1566 /* When the test is controlled by byte count, the time test will */
1567 /* always return false. When the test is finished, the whole */
1568 /* expression will go false and we will stop sending data. I think I */
1569 /* just arbitrarily decrement trans_remaining for the timed test, but */
1570 /* will not do that just yet... One other question is whether or not */
1571 /* the send buffer and the receive buffer should be the same buffer. */
1572
1573 while ((!times_up) || (trans_remaining > 0)) {
1574 /* send the request */
1575 if((putmsg(send_descriptor,
1576 0,
1577 &send_message,
1578 0)) != 0) {
1579 if (errno == EINTR) {
1580 /* we hit the end of a */
1581 /* timed test. */
1582 timed_out = 1;
1583 break;
1584 }
1585 perror("send_dlpi_co_rr: putmsg error");
1586 exit(1);
1587 }
1588
1589 if (debug) {
1590 fprintf(where,"recv_message.len %d\n",recv_message.len);
1591 fprintf(where,"send_message.len %d\n",send_message.len);
1592 fflush(where);
1593 }
1594
1595 /* receive the response */
1596 /* this needs some work with streams buffers if we are going to */
1597 /* support requests and responses larger than the MTU of the */
1598 /* network, but this can wait until later */
1599 rsp_bytes_left = rsp_size;
1600 recv_message.len = rsp_size;
1601 while(rsp_bytes_left > 0) {
1602 if((getmsg(send_descriptor,
1603 0,
1604 &recv_message,
1605 &flags)) < 0) {
1606 if (errno == EINTR) {
1607 /* We hit the end of a timed test. */
1608 timed_out = 1;
1609 break;
1610 }
1611 perror("send_dlpi_co_rr: data recv error");
1612 exit(1);
1613 }
1614 rsp_bytes_left -= recv_message.len;
1615 }
1616
1617 if (timed_out) {
1618 /* we may have been in a nested while loop - we need */
1619 /* another call to break. */
1620 break;
1621 }
1622
1623 nummessages++;
1624 if (trans_remaining) {
1625 trans_remaining--;
1626 }
1627
1628 if (debug > 3) {
1629 fprintf(where,
1630 "Transaction %d completed\n",
1631 nummessages);
1632 fflush(where);
1633 }
1634 }
1635
1636 /* At this point we used to call shutdown onthe data socket to be */
1637 /* sure all the data was delivered, but this was not germane in a */
1638 /* request/response test, and it was causing the tests to "hang" when */
1639 /* they were being controlled by time. So, I have replaced this */
1640 /* shutdown call with a call to close that can be found later in the */
1641 /* procedure. */
1642
1643 /* this call will always give us the elapsed time for the test, and */
1644 /* will also store-away the necessaries for cpu utilization */
1645
1646 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
1647 /* how long did we really run? */
1648
1649 /* Get the statistics from the remote end. The remote will have */
1650 /* calculated service demand and all those interesting things. If it */
1651 /* wasn't supposed to care, it will return obvious values. */
1652
1653 recv_response();
1654 if (!netperf_response.content.serv_errno) {
1655 if (debug)
1656 fprintf(where,"remote results obtained\n");
1657 }
1658 else {
1659 Set_errno(netperf_response.content.serv_errno);
1660 perror("netperf: remote error");
1661
1662 exit(1);
1663 }
1664
1665 /* We now calculate what our thruput was for the test. In the future, */
1666 /* we may want to include a calculation of the thruput measured by */
1667 /* the remote, but it should be the case that for a TCP stream test, */
1668 /* that the two numbers should be *very* close... We calculate */
1669 /* bytes_sent regardless of the way the test length was controlled. */
1670 /* If it was time, we needed to, and if it was by bytes, the user may */
1671 /* have specified a number of bytes that wasn't a multiple of the */
1672 /* send_size, so we really didn't send what he asked for ;-) We use */
1673 /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
1674 /* 1024. A future enhancement *might* be to choose from a couple of */
1675 /* unit selections. */
1676
1677 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
1678 thruput = calc_thruput(bytes_xferd);
1679
1680 if (local_cpu_usage || remote_cpu_usage) {
1681 /* We must now do a little math for service demand and cpu */
1682 /* utilization for the system(s) */
1683 /* Of course, some of the information might be bogus because */
1684 /* there was no idle counter in the kernel(s). We need to make */
1685 /* a note of this for the user's benefit...*/
1686 if (local_cpu_usage) {
1687 if (local_cpu_rate == 0.0) {
1688 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
1689 fprintf(where,"Local CPU usage numbers based on process information only!\n");
1690 fflush(where);
1691 }
1692 local_cpu_utilization = calc_cpu_util(0.0);
1693 /* since calc_service demand is doing ms/Kunit we will */
1694 /* multiply the number of transaction by 1024 to get */
1695 /* "good" numbers */
1696 local_service_demand = calc_service_demand((double) nummessages*1024,
1697 0.0,
1698 0.0,
1699 0);
1700 }
1701 else {
1702 local_cpu_utilization = -1.0;
1703 local_service_demand = -1.0;
1704 }
1705
1706 if (remote_cpu_usage) {
1707 if (remote_cpu_rate == 0.0) {
1708 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
1709 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
1710 fflush(where);
1711 }
1712 remote_cpu_utilization = dlpi_co_rr_result->cpu_util;
1713 /* since calc_service demand is doing ms/Kunit we will */
1714 /* multiply the number of transaction by 1024 to get */
1715 /* "good" numbers */
1716 remote_service_demand = calc_service_demand((double) nummessages*1024,
1717 0.0,
1718 remote_cpu_utilization,
1719 dlpi_co_rr_result->num_cpus);
1720 }
1721 else {
1722 remote_cpu_utilization = -1.0;
1723 remote_service_demand = -1.0;
1724 }
1725
1726 /* We are now ready to print all the information. If the user */
1727 /* has specified zero-level verbosity, we will just print the */
1728 /* local service demand, or the remote service demand. If the */
1729 /* user has requested verbosity level 1, he will get the basic */
1730 /* "streamperf" numbers. If the user has specified a verbosity */
1731 /* of greater than 1, we will display a veritable plethora of */
1732 /* background information from outside of this block as it it */
1733 /* not cpu_measurement specific... */
1734
1735 switch (verbosity) {
1736 case 0:
1737 if (local_cpu_usage) {
1738 fprintf(where,
1739 cpu_fmt_0,
1740 local_service_demand);
1741 }
1742 else {
1743 fprintf(where,
1744 cpu_fmt_0,
1745 remote_service_demand);
1746 }
1747 break;
1748 case 1:
1749 fprintf(where,
1750 cpu_fmt_1_line_1, /* the format string */
1751 lsw_size, /* local sendbuf size */
1752 lrw_size,
1753 req_size, /* how large were the requests */
1754 rsp_size, /* guess */
1755 elapsed_time, /* how long was the test */
1756 nummessages/elapsed_time,
1757 local_cpu_utilization, /* local cpu */
1758 remote_cpu_utilization, /* remote cpu */
1759 local_service_demand, /* local service demand */
1760 remote_service_demand); /* remote service demand */
1761 fprintf(where,
1762 cpu_fmt_1_line_2,
1763 rsw_size,
1764 rrw_size);
1765 break;
1766 }
1767 }
1768 else {
1769 /* The tester did not wish to measure service demand. */
1770 switch (verbosity) {
1771 case 0:
1772 fprintf(where,
1773 tput_fmt_0,
1774 nummessages/elapsed_time);
1775 break;
1776 case 1:
1777 fprintf(where,
1778 tput_fmt_1_line_1, /* the format string */
1779 lsw_size,
1780 lrw_size,
1781 req_size, /* how large were the requests */
1782 rsp_size, /* how large were the responses */
1783 elapsed_time, /* how long did it take */
1784 nummessages/elapsed_time);
1785 fprintf(where,
1786 tput_fmt_1_line_2,
1787 rsw_size, /* remote recvbuf size */
1788 rrw_size);
1789
1790 break;
1791 }
1792 }
1793
1794 /* it would be a good thing to include information about some of the */
1795 /* other parameters that may have been set for this test, but at the */
1796 /* moment, I do not wish to figure-out all the formatting, so I will */
1797 /* just put this comment here to help remind me that it is something */
1798 /* that should be done at a later time. */
1799
1800 if (verbosity > 1) {
1801 /* The user wanted to know it all, so we will give it to him. */
1802 /* This information will include as much as we can find about */
1803 /* TCP statistics, the alignments of the sends and receives */
1804 /* and all that sort of rot... */
1805
1806 fprintf(where,
1807 ksink_fmt);
1808 }
1809 /* The test is over. Kill the data descriptor */
1810
1811 if (close(send_descriptor) == -1) {
1812 perror("send_dlpi_co_rr: cannot shutdown tcp stream descriptor");
1813 }
1814
1815 }
1816
1817 void
send_dlpi_cl_stream(char remote_host[])1818 send_dlpi_cl_stream(char remote_host[])
1819 {
1820 /************************************************************************/
1821 /* */
1822 /* UDP Unidirectional Send Test */
1823 /* */
1824 /************************************************************************/
1825 char *tput_title =
1826 "Window Message Elapsed Messages \n\
1827 Size Size Time Okay Errors Throughput\n\
1828 frames bytes secs # # %s/sec\n\n";
1829
1830 char *tput_fmt_0 =
1831 "%7.2f\n";
1832
1833 char *tput_fmt_1 =
1834 "%5d %5d %-7.2f %7d %6d %7.2f\n\
1835 %5d %-7.2f %7d %7.2f\n\n";
1836
1837
1838 char *cpu_title =
1839 "Window Message Elapsed Messages CPU Service\n\
1840 Size Size Time Okay Errors Throughput Util Demand\n\
1841 frames bytes secs # # %s/sec %% us/KB\n\n";
1842
1843 char *cpu_fmt_0 =
1844 "%6.2f\n";
1845
1846 char *cpu_fmt_1 =
1847 "%5d %5d %-7.2f %7d %6d %7.1f %-6.2f %-6.3f\n\
1848 %5d %-7.2f %7d %7.1f %-6.2f %-6.3f\n\n";
1849
1850 int messages_recvd;
1851 float elapsed_time,
1852 local_cpu_utilization,
1853 remote_cpu_utilization;
1854
1855 float local_service_demand, remote_service_demand;
1856 double local_thruput, remote_thruput;
1857 double bytes_sent;
1858 double bytes_recvd;
1859
1860
1861 int *message_int_ptr;
1862 char *message_ptr;
1863 char *message;
1864 char sctl_data[BUFSIZ];
1865 struct strbuf send_message;
1866 struct strbuf sctl_message;
1867 dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
1868
1869 char dlsap[BUFSIZ];
1870 int dlsap_len;
1871 int message_offset;
1872 int message_max_offset;
1873 int failed_sends;
1874 int failed_cows;
1875 int messages_sent;
1876 int data_descriptor;
1877
1878
1879 #ifdef WANT_INTERVALS
1880 int interval_count;
1881 #endif /* WANT_INTERVALS */
1882 #ifdef DIRTY
1883 int i;
1884 #endif /* DIRTY */
1885
1886 struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request;
1887 struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response;
1888 struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results;
1889
1890 dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
1891 dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
1892 dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
1893
1894 if ( print_headers ) {
1895 printf("DLPI CL UNIDIRECTIONAL SEND TEST\n");
1896 if (local_cpu_usage || remote_cpu_usage)
1897 printf(cpu_title,format_units());
1898 else
1899 printf(tput_title,format_units());
1900 }
1901
1902 failed_sends = 0;
1903 messages_sent = 0;
1904 times_up = 0;
1905
1906 /*set up the data descriptor */
1907
1908 data_descriptor = dl_open(loc_dlpi_device,loc_ppa);
1909 if (data_descriptor < 0){
1910 perror("send_dlpi_cl_stream: data descriptor");
1911 exit(1);
1912 }
1913
1914 /* bind the puppy and get the assigned dlsap */
1915 dlsap_len = BUFSIZ;
1916 if (dl_bind(data_descriptor,
1917 dlpi_sap, DL_CLDLS, dlsap, &dlsap_len) != 0) {
1918 fprintf(where,"send_dlpi_cl_stream: bind failure\n");
1919 fflush(where);
1920 exit(1);
1921 }
1922
1923 /* Modify the local socket size (SNDBUF size) */
1924
1925 #ifdef DL_HP_SET_LOCAL_WIN_REQ
1926 if (lsw_size > 0) {
1927 if (debug > 1) {
1928 fprintf(where,"netperf: send_dlpi_cl_stream: descriptor send size altered from system default...\n");
1929 fprintf(where," send: %d\n",lsw_size);
1930 }
1931 }
1932 if (lrw_size > 0) {
1933 if (debug > 1) {
1934 fprintf(where,"netperf: send_dlpi_cl_stream: descriptor recv size altered from system default...\n");
1935 fprintf(where," recv: %d\n",lrw_size);
1936 }
1937 }
1938
1939
1940 /* Now, we will find-out what the size actually became, and report */
1941 /* that back to the user. If the call fails, we will just report a -1 */
1942 /* back to the initiator for the recv buffer size. */
1943
1944 #else /* DL_HP_SET_LOCAL_WIN_REQ */
1945
1946 lsw_size = -1;
1947 lrw_size = -1;
1948
1949 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
1950
1951 /* now, we want to see if we need to set the send_size */
1952 if (send_size == 0) {
1953 send_size = 1024;
1954 }
1955
1956
1957 /* set-up the data buffer with the requested alignment and offset, */
1958 /* most of the numbers here are just a hack to pick something nice */
1959 /* and big in an attempt to never try to send a buffer a second time */
1960 /* before it leaves the node...unless the user set the width */
1961 /* explicitly. */
1962 if (send_width == 0) send_width = 32;
1963 message = (char *)malloc(send_size * (send_width + 1) + local_send_align + local_send_offset);
1964 if (message == NULL) {
1965 printf("malloc(%d) failed!\n", send_size * (send_width + 1) + local_send_align + local_send_offset);
1966 exit(1);
1967 }
1968 message_ptr = (char *)(( (long) message +
1969 (long) local_send_align - 1) &
1970 ~((long) local_send_align - 1));
1971 message_ptr = message_ptr + local_send_offset;
1972 message = message_ptr;
1973 send_message.maxlen = send_size;
1974 send_message.len = send_size;
1975 send_message.buf = message;
1976
1977 sctl_message.maxlen = BUFSIZ;
1978 sctl_message.len = 0;
1979 sctl_message.buf = sctl_data;
1980
1981 /* if the user supplied a cpu rate, this call will complete rather */
1982 /* quickly, otherwise, the cpu rate will be retured to us for */
1983 /* possible display. The Library will keep it's own copy of this data */
1984 /* for use elsewhere. We will only display it. (Does that make it */
1985 /* "opaque" to us?) */
1986
1987 if (local_cpu_usage)
1988 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1989
1990 /* Tell the remote end to set up the data connection. The server */
1991 /* sends back the port number and alters the socket parameters there. */
1992 /* Of course this is a datagram service so no connection is actually */
1993 /* set up, the server just sets up the socket and binds it. */
1994
1995 netperf_request.content.request_type = DO_DLPI_CL_STREAM;
1996 dlpi_cl_stream_request->recv_win_size = rrw_size;
1997 dlpi_cl_stream_request->message_size = send_size;
1998 dlpi_cl_stream_request->recv_alignment = remote_recv_align;
1999 dlpi_cl_stream_request->recv_offset = remote_recv_offset;
2000 dlpi_cl_stream_request->measure_cpu = remote_cpu_usage;
2001 dlpi_cl_stream_request->cpu_rate = remote_cpu_rate;
2002 dlpi_cl_stream_request->ppa = rem_ppa;
2003 dlpi_cl_stream_request->sap = dlpi_sap;
2004 dlpi_cl_stream_request->dev_name_len = strlen(rem_dlpi_device);
2005 strcpy(dlpi_cl_stream_request->dlpi_device,
2006 rem_dlpi_device);
2007
2008 #ifdef __alpha
2009
2010 /* ok - even on a DEC box, strings are strings. I din't really want */
2011 /* to ntohl the words of a string. since I don't want to teach the */
2012 /* send_ and recv_ _request and _response routines about the types, */
2013 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2014 /* solution would be to use XDR, but I am still leary of being able */
2015 /* to find XDR libs on all platforms I want running netperf. raj */
2016 {
2017 int *charword;
2018 int *initword;
2019 int *lastword;
2020
2021 initword = (int *) dlpi_cl_stream_request->dlpi_device;
2022 lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
2023
2024 for (charword = initword;
2025 charword < lastword;
2026 charword++) {
2027
2028 *charword = ntohl(*charword);
2029 }
2030 }
2031 #endif /* __alpha */
2032
2033 if (test_time) {
2034 dlpi_cl_stream_request->test_length = test_time;
2035 }
2036 else {
2037 dlpi_cl_stream_request->test_length = test_bytes * -1;
2038 }
2039
2040
2041 send_request();
2042
2043 recv_response();
2044
2045 if (!netperf_response.content.serv_errno) {
2046 if (debug)
2047 fprintf(where,"send_dlpi_cl_stream: remote data connection done.\n");
2048 }
2049 else {
2050 Set_errno(netperf_response.content.serv_errno);
2051 perror("send_dlpi_cl_stream: error on remote");
2052 exit(1);
2053 }
2054
2055 /* place some of the remote's addressing information into the send */
2056 /* structure so our sends can be sent to the correct place. Also get */
2057 /* some of the returned socket buffer information for user display. */
2058
2059 /* set-up the destination addressing control info */
2060 data_req->dl_primitive = DL_UNITDATA_REQ;
2061 bcopy((char *)(dlpi_cl_stream_response->station_addr),
2062 ((char *)data_req + sizeof(dl_unitdata_req_t)),
2063 dlpi_cl_stream_response->station_addr_len);
2064 data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
2065 data_req->dl_dest_addr_length = dlpi_cl_stream_response->station_addr_len;
2066 /* there is a dl_priority structure too, but I am ignoring it for */
2067 /* the time being. */
2068 /* however... it is best to put some value in there lest some code
2069 get grumpy about it - fix from Nicolas Thomas */
2070 data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
2071 data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
2072
2073 sctl_message.len = sizeof(dl_unitdata_req_t) +
2074 data_req->dl_dest_addr_length;
2075
2076 rrw_size = dlpi_cl_stream_response->recv_win_size;
2077 rsw_size = dlpi_cl_stream_response->send_win_size;
2078 remote_cpu_rate = dlpi_cl_stream_response->cpu_rate;
2079
2080
2081 /* set up the timer to call us after test_time */
2082 start_timer(test_time);
2083
2084 /* Get the start count for the idle counter and the start time */
2085
2086 cpu_start(local_cpu_usage);
2087
2088 #ifdef WANT_INTERVALS
2089 interval_count = interval_burst;
2090 #endif /* WANT_INTERVALS */
2091
2092 /* Send datagrams like there was no tomorrow */
2093 while (!times_up) {
2094 #ifdef DIRTY
2095 /* we want to dirty some number of consecutive integers in the buffer */
2096 /* we are about to send. we may also want to bring some number of */
2097 /* them cleanly into the cache. The clean ones will follow any dirty */
2098 /* ones into the cache. */
2099 message_int_ptr = (int *)message_ptr;
2100 for (i = 0; i < loc_dirty_count; i++) {
2101 *message_int_ptr = 4;
2102 message_int_ptr++;
2103 }
2104 for (i = 0; i < loc_clean_count; i++) {
2105 loc_dirty_count = *message_int_ptr;
2106 message_int_ptr++;
2107 }
2108 #endif /* DIRTY */
2109 if (putmsg(data_descriptor,
2110 &sctl_message,
2111 &send_message,
2112 0) != 0) {
2113 if (errno == EINTR) {
2114 break;
2115 }
2116 if (errno == ENOBUFS) {
2117 /* we might not ever hit this with STREAMS, it would probably */
2118 /* be better to do a getinfo request at the end of the test to */
2119 /* get all sorts of gory statistics. in the meantime, we will */
2120 /* keep this code in place. */
2121 failed_sends++;
2122 continue;
2123 }
2124 perror("send_dlpi_cl_stream: data send error");
2125 if (debug) {
2126 fprintf(where,"messages_sent %u\n",messages_sent);
2127 fflush(where);
2128 }
2129 exit(1);
2130 }
2131 messages_sent++;
2132
2133 /* now we want to move our pointer to the next position in the */
2134 /* data buffer...since there was a successful send */
2135
2136
2137 #ifdef WANT_INTERVALS
2138 /* in this case, the interval count is the count-down couter */
2139 /* to decide to sleep for a little bit */
2140 if ((interval_burst) && (--interval_count == 0)) {
2141 /* call the sleep routine for some milliseconds, if our */
2142 /* timer popped while we were in there, we want to */
2143 /* break out of the loop. */
2144 if (msec_sleep(interval_wate)) {
2145 break;
2146 }
2147 interval_count = interval_burst;
2148 }
2149
2150 #endif /* WANT_INTERVALS */
2151
2152 }
2153
2154 /* This is a timed test, so the remote will be returning to us after */
2155 /* a time. We should not need to send any "strange" messages to tell */
2156 /* the remote that the test is completed, unless we decide to add a */
2157 /* number of messages to the test. */
2158
2159 /* the test is over, so get stats and stuff */
2160 cpu_stop(local_cpu_usage,
2161 &elapsed_time);
2162
2163 /* Get the statistics from the remote end */
2164 recv_response();
2165 if (!netperf_response.content.serv_errno) {
2166 if (debug)
2167 fprintf(where,"send_dlpi_cl_stream: remote results obtained\n");
2168 }
2169 else {
2170 Set_errno(netperf_response.content.serv_errno);
2171 perror("send_dlpi_cl_stream: error on remote");
2172 exit(1);
2173 }
2174
2175 bytes_sent = send_size * messages_sent;
2176 local_thruput = calc_thruput(bytes_sent);
2177
2178 messages_recvd = dlpi_cl_stream_results->messages_recvd;
2179 bytes_recvd = send_size * messages_recvd;
2180
2181 /* we asume that the remote ran for as long as we did */
2182
2183 remote_thruput = calc_thruput(bytes_recvd);
2184
2185 /* print the results for this descriptor and message size */
2186
2187 if (local_cpu_usage || remote_cpu_usage) {
2188 /* We must now do a little math for service demand and cpu */
2189 /* utilization for the system(s) We pass zeros for the local */
2190 /* cpu utilization and elapsed time to tell the routine to use */
2191 /* the libraries own values for those. */
2192 if (local_cpu_usage) {
2193 if (local_cpu_rate == 0.0) {
2194 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
2195 fprintf(where,"Local CPU usage numbers based on process information only!\n");
2196 fflush(where);
2197 }
2198
2199 local_cpu_utilization = calc_cpu_util(0.0);
2200 local_service_demand = calc_service_demand(bytes_sent,
2201 0.0,
2202 0.0,
2203 0);
2204 }
2205 else {
2206 local_cpu_utilization = -1.0;
2207 local_service_demand = -1.0;
2208 }
2209
2210 /* The local calculations could use variables being kept by */
2211 /* the local netlib routines. The remote calcuations need to */
2212 /* have a few things passed to them. */
2213 if (remote_cpu_usage) {
2214 if (remote_cpu_rate == 0.0) {
2215 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
2216 fprintf(where,"REMOTE CPU usage numbers based on process information only!\n");
2217 fflush(where);
2218 }
2219
2220 remote_cpu_utilization = dlpi_cl_stream_results->cpu_util;
2221 remote_service_demand = calc_service_demand(bytes_recvd,
2222 0.0,
2223 remote_cpu_utilization,
2224 dlpi_cl_stream_results->num_cpus);
2225 }
2226 else {
2227 remote_cpu_utilization = -1.0;
2228 remote_service_demand = -1.0;
2229 }
2230
2231 /* We are now ready to print all the information. If the user */
2232 /* has specified zero-level verbosity, we will just print the */
2233 /* local service demand, or the remote service demand. If the */
2234 /* user has requested verbosity level 1, he will get the basic */
2235 /* "streamperf" numbers. If the user has specified a verbosity */
2236 /* of greater than 1, we will display a veritable plethora of */
2237 /* background information from outside of this block as it it */
2238 /* not cpu_measurement specific... */
2239
2240 switch (verbosity) {
2241 case 0:
2242 if (local_cpu_usage) {
2243 fprintf(where,
2244 cpu_fmt_0,
2245 local_service_demand);
2246 }
2247 else {
2248 fprintf(where,
2249 cpu_fmt_0,
2250 remote_service_demand);
2251 }
2252 break;
2253 case 1:
2254 fprintf(where,
2255 cpu_fmt_1, /* the format string */
2256 lsw_size, /* local sendbuf size */
2257 send_size, /* how large were the sends */
2258 elapsed_time, /* how long was the test */
2259 messages_sent,
2260 failed_sends,
2261 local_thruput, /* what was the xfer rate */
2262 local_cpu_utilization, /* local cpu */
2263 local_service_demand, /* local service demand */
2264 rrw_size,
2265 elapsed_time,
2266 messages_recvd,
2267 remote_thruput,
2268 remote_cpu_utilization, /* remote cpu */
2269 remote_service_demand); /* remote service demand */
2270 break;
2271 }
2272 }
2273 else {
2274 /* The tester did not wish to measure service demand. */
2275 switch (verbosity) {
2276 case 0:
2277 fprintf(where,
2278 tput_fmt_0,
2279 local_thruput);
2280 break;
2281 case 1:
2282 fprintf(where,
2283 tput_fmt_1, /* the format string */
2284 lsw_size, /* local sendbuf size */
2285 send_size, /* how large were the sends */
2286 elapsed_time, /* how long did it take */
2287 messages_sent,
2288 failed_sends,
2289 local_thruput,
2290 rrw_size, /* remote recvbuf size */
2291 elapsed_time,
2292 messages_recvd,
2293 remote_thruput
2294 );
2295 break;
2296 }
2297 }
2298 }
2299
2300 int
recv_dlpi_cl_stream()2301 recv_dlpi_cl_stream()
2302 {
2303
2304 char *message;
2305 int data_descriptor;
2306 int len;
2307 char *message_ptr;
2308 char rctl_data[BUFSIZ];
2309 struct strbuf recv_message;
2310 struct strbuf rctl_message;
2311 int flags = 0;
2312 /* these are to make reading some of the DLPI control messages easier */
2313 dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
2314 dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data;
2315
2316 int bytes_received = 0;
2317 float elapsed_time;
2318
2319 int message_size;
2320 int messages_recvd = 0;
2321 int measure_cpu;
2322
2323 struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request;
2324 struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response;
2325 struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results;
2326
2327 dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
2328 dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
2329 dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
2330
2331 if (debug) {
2332 fprintf(where,"netserver: recv_dlpi_cl_stream: entered...\n");
2333 fflush(where);
2334 }
2335
2336 /* We want to set-up the listen descriptor with all the desired */
2337 /* parameters and then let the initiator know that all is ready. If */
2338 /* socket size defaults are to be used, then the initiator will have */
2339 /* sent us 0's. If the socket sizes cannot be changed, then we will */
2340 /* send-back what they are. If that information cannot be determined, */
2341 /* then we send-back -1's for the sizes. If things go wrong for any */
2342 /* reason, we will drop back ten yards and punt. */
2343
2344 /* If anything goes wrong, we want the remote to know about it. It */
2345 /* would be best if the error that the remote reports to the user is */
2346 /* the actual error we encountered, rather than some bogus unexpected */
2347 /* response type message. */
2348
2349 if (debug > 1) {
2350 fprintf(where,"recv_dlpi_cl_stream: setting the response type...\n");
2351 fflush(where);
2352 }
2353
2354 netperf_response.content.response_type = DLPI_CL_STREAM_RESPONSE;
2355
2356 if (debug > 2) {
2357 fprintf(where,"recv_dlpi_cl_stream: the response type is set...\n");
2358 fflush(where);
2359 }
2360
2361 /* set-up the data buffer with the requested alignment and offset */
2362 message = (char *)malloc(DATABUFFERLEN);
2363 if (message == NULL) {
2364 printf("malloc(%d) failed!\n", DATABUFFERLEN);
2365 exit(1);
2366 }
2367
2368 /* We now alter the message_ptr variable to be at the desired */
2369 /* alignment with the desired offset. */
2370
2371 if (debug > 1) {
2372 fprintf(where,"recv_dlpi_cl_stream: requested alignment of %d\n",
2373 dlpi_cl_stream_request->recv_alignment);
2374 fflush(where);
2375 }
2376
2377 message_ptr = ALIGN_BUFFER(message, dlpi_cl_stream_request->recv_alignment, dlpi_cl_stream_request->recv_offset);
2378
2379 if (dlpi_cl_stream_request->message_size > 0) {
2380 recv_message.maxlen = dlpi_cl_stream_request->message_size;
2381 }
2382 else {
2383 recv_message.maxlen = 4096;
2384 }
2385 recv_message.len = 0;
2386 recv_message.buf = message_ptr;
2387
2388 rctl_message.maxlen = BUFSIZ;
2389 rctl_message.len = 0;
2390 rctl_message.buf = rctl_data;
2391
2392 if (debug > 1) {
2393 fprintf(where,
2394 "recv_dlpi_cl_stream: receive alignment and offset set...\n");
2395 fflush(where);
2396 }
2397
2398 if (debug > 1) {
2399 fprintf(where,"recv_dlpi_cl_stream: grabbing a descriptor...\n");
2400 fflush(where);
2401 }
2402
2403 #ifdef __alpha
2404
2405 /* ok - even on a DEC box, strings are strings. I din't really want */
2406 /* to ntohl the words of a string. since I don't want to teach the */
2407 /* send_ and recv_ _request and _response routines about the types, */
2408 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2409 /* solution would be to use XDR, but I am still leary of being able */
2410 /* to find XDR libs on all platforms I want running netperf. raj */
2411 {
2412 int *charword;
2413 int *initword;
2414 int *lastword;
2415
2416 initword = (int *) dlpi_cl_stream_request->dlpi_device;
2417 lastword = initword + ((dlpi_cl_stream_request->dev_name_len + 3) / 4);
2418
2419 for (charword = initword;
2420 charword < lastword;
2421 charword++) {
2422
2423 *charword = htonl(*charword);
2424 }
2425 }
2426 #endif /* __alpha */
2427
2428 data_descriptor = dl_open(dlpi_cl_stream_request->dlpi_device,
2429 dlpi_cl_stream_request->ppa);
2430 if (data_descriptor < 0) {
2431 netperf_response.content.serv_errno = errno;
2432 send_response();
2433 exit(1);
2434 }
2435
2436 /* The initiator may have wished-us to modify the window */
2437 /* sizes. We should give it a shot. If he didn't ask us to change the */
2438 /* sizes, we should let him know what sizes were in use at this end. */
2439 /* If none of this code is compiled-in, then we will tell the */
2440 /* initiator that we were unable to play with the sizes by */
2441 /* setting the size in the response to -1. */
2442
2443 #ifdef DL_HP_SET_LOCAL_WIN_REQ
2444
2445 if (dlpi_cl_stream_request->recv_win_size) {
2446 dlpi_cl_stream_response->recv_win_size = -1;
2447 }
2448
2449 #else /* the system won't let us play with the buffers */
2450
2451 dlpi_cl_stream_response->recv_win_size = -1;
2452
2453 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
2454
2455 dlpi_cl_stream_response->test_length = dlpi_cl_stream_request->test_length;
2456
2457 /* bind the sap and retrieve the dlsap assigned by the system */
2458 dlpi_cl_stream_response->station_addr_len = 14; /* arbitrary */
2459 if (dl_bind(data_descriptor,
2460 dlpi_cl_stream_request->sap,
2461 DL_CLDLS,
2462 (char *)dlpi_cl_stream_response->station_addr,
2463 &dlpi_cl_stream_response->station_addr_len) != 0) {
2464 fprintf(where,"send_dlpi_cl_stream: bind failure\n");
2465 fflush(where);
2466 exit(1);
2467 }
2468
2469 netperf_response.content.serv_errno = 0;
2470
2471 /* But wait, there's more. If the initiator wanted cpu measurements, */
2472 /* then we must call the calibrate routine, which will return the max */
2473 /* rate back to the initiator. If the CPU was not to be measured, or */
2474 /* something went wrong with the calibration, we will return a -1 to */
2475 /* the initiator. */
2476
2477 dlpi_cl_stream_response->cpu_rate = 0.0; /* assume no cpu */
2478 if (dlpi_cl_stream_request->measure_cpu) {
2479 /* We will pass the rate into the calibration routine. If the */
2480 /* user did not specify one, it will be 0.0, and we will do a */
2481 /* "real" calibration. Otherwise, all it will really do is */
2482 /* store it away... */
2483 dlpi_cl_stream_response->measure_cpu = 1;
2484 dlpi_cl_stream_response->cpu_rate = calibrate_local_cpu(dlpi_cl_stream_request->cpu_rate);
2485 }
2486
2487 message_size = dlpi_cl_stream_request->message_size;
2488 test_time = dlpi_cl_stream_request->test_length;
2489
2490 send_response();
2491
2492 /* Now it's time to start receiving data on the connection. We will */
2493 /* first grab the apropriate counters and then start grabbing. */
2494
2495 cpu_start(dlpi_cl_stream_request->measure_cpu);
2496
2497 /* The loop will exit when the timer pops, or if we happen to recv a */
2498 /* message of less than send_size bytes... */
2499
2500 times_up = 0;
2501 start_timer(test_time + PAD_TIME);
2502
2503 if (debug) {
2504 fprintf(where,"recv_dlpi_cl_stream: about to enter inner sanctum.\n");
2505 fflush(where);
2506 }
2507
2508 while (!times_up) {
2509 if((getmsg(data_descriptor,
2510 &rctl_message,
2511 &recv_message,
2512 &flags) != 0) ||
2513 (data_ind->dl_primitive != DL_UNITDATA_IND)) {
2514 if (errno == EINTR) {
2515 /* Again, we have likely hit test-end time */
2516 break;
2517 }
2518 fprintf(where,
2519 "dlpi_recv_cl_stream: getmsg failure: errno %d primitive 0x%x\n",
2520 errno,
2521 data_ind->dl_primitive);
2522 fflush(where);
2523 netperf_response.content.serv_errno = 996;
2524 send_response();
2525 exit(1);
2526 }
2527 messages_recvd++;
2528 }
2529
2530 if (debug) {
2531 fprintf(where,"recv_dlpi_cl_stream: got %d messages.\n",messages_recvd);
2532 fflush(where);
2533 }
2534
2535
2536 /* The loop now exits due timer or < send_size bytes received. */
2537
2538 cpu_stop(dlpi_cl_stream_request->measure_cpu,&elapsed_time);
2539
2540 if (times_up) {
2541 /* we ended on a timer, subtract the PAD_TIME */
2542 elapsed_time -= (float)PAD_TIME;
2543 }
2544 else {
2545 stop_timer();
2546 }
2547
2548 if (debug) {
2549 fprintf(where,"recv_dlpi_cl_stream: test ended in %f seconds.\n",elapsed_time);
2550 fflush(where);
2551 }
2552
2553
2554 /* We will count the "off" message */
2555 bytes_received = (messages_recvd * message_size) + len;
2556
2557 /* send the results to the sender */
2558
2559 if (debug) {
2560 fprintf(where,
2561 "recv_dlpi_cl_stream: got %d bytes\n",
2562 bytes_received);
2563 fflush(where);
2564 }
2565
2566 netperf_response.content.response_type = DLPI_CL_STREAM_RESULTS;
2567 dlpi_cl_stream_results->bytes_received = bytes_received;
2568 dlpi_cl_stream_results->messages_recvd = messages_recvd;
2569 dlpi_cl_stream_results->elapsed_time = elapsed_time;
2570 if (dlpi_cl_stream_request->measure_cpu) {
2571 dlpi_cl_stream_results->cpu_util = calc_cpu_util(elapsed_time);
2572 }
2573 else {
2574 dlpi_cl_stream_results->cpu_util = -1.0;
2575 }
2576
2577 if (debug > 1) {
2578 fprintf(where,
2579 "recv_dlpi_cl_stream: test complete, sending results.\n");
2580 fflush(where);
2581 }
2582
2583 send_response();
2584
2585 }
2586
send_dlpi_cl_rr(char remote_host[])2587 int send_dlpi_cl_rr(char remote_host[])
2588 {
2589
2590 char *tput_title = "\
2591 Local /Remote\n\
2592 Window Size Request Resp. Elapsed Trans.\n\
2593 Send Recv Size Size Time Rate \n\
2594 frames frames bytes bytes secs. per sec \n\n";
2595
2596 char *tput_fmt_0 =
2597 "%7.2f\n";
2598
2599 char *tput_fmt_1_line_1 = "\
2600 %-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
2601 char *tput_fmt_1_line_2 = "\
2602 %-6d %-6d\n";
2603
2604 char *cpu_title = "\
2605 Local /Remote\n\
2606 Window Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
2607 Send Recv Size Size Time Rate local remote local remote\n\
2608 frames frames bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
2609
2610 char *cpu_fmt_0 =
2611 "%6.3f\n";
2612
2613 char *cpu_fmt_1_line_1 = "\
2614 %-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
2615
2616 char *cpu_fmt_1_line_2 = "\
2617 %-6d %-6d\n";
2618
2619 char *ksink_fmt = "\
2620 Alignment Offset\n\
2621 Local Remote Local Remote\n\
2622 Send Recv Send Recv\n\
2623 %5d %5d %5d %5d\n";
2624
2625
2626 float elapsed_time;
2627
2628 int dlsap_len;
2629 int flags = 0;
2630 char *send_message_ptr;
2631 char *recv_message_ptr;
2632 char *temp_message_ptr;
2633 char sctl_data[BUFSIZ];
2634 char rctl_data[BUFSIZ];
2635 char dlsap[BUFSIZ];
2636 struct strbuf send_message;
2637 struct strbuf recv_message;
2638 struct strbuf sctl_message;
2639 struct strbuf rctl_message;
2640
2641 /* these are to make reading some of the DLPI control messages easier */
2642 dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
2643 dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
2644 dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data;
2645
2646 int nummessages;
2647 int send_descriptor;
2648 int trans_remaining;
2649 int bytes_xferd;
2650
2651 float local_cpu_utilization;
2652 float local_service_demand;
2653 float remote_cpu_utilization;
2654 float remote_service_demand;
2655 double thruput;
2656
2657 #ifdef WANT_INTERVALS
2658 /* timing stuff */
2659 #define MAX_KEPT_TIMES 1024
2660 int time_index = 0;
2661 int unused_buckets;
2662 int kept_times[MAX_KEPT_TIMES];
2663 int sleep_usecs;
2664 unsigned int total_times=0;
2665 struct timezone dummy_zone;
2666 struct timeval send_time;
2667 struct timeval recv_time;
2668 struct timeval sleep_timeval;
2669 #endif /* WANT_INTERVALS */
2670
2671 struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request;
2672 struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response;
2673 struct dlpi_cl_rr_results_struct *dlpi_cl_rr_result;
2674
2675 dlpi_cl_rr_request =
2676 (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
2677 dlpi_cl_rr_response =
2678 (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
2679 dlpi_cl_rr_result =
2680 (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
2681
2682 /* we want to zero out the times, so we can detect unused entries. */
2683 #ifdef WANT_INTERVALS
2684 time_index = 0;
2685 while (time_index < MAX_KEPT_TIMES) {
2686 kept_times[time_index] = 0;
2687 time_index += 1;
2688 }
2689 time_index = 0;
2690 #endif /* WANT_INTERVALS */
2691
2692 if (print_headers) {
2693 fprintf(where,"DLPI CL REQUEST/RESPONSE TEST\n");
2694 if (local_cpu_usage || remote_cpu_usage)
2695 fprintf(where,cpu_title,format_units());
2696 else
2697 fprintf(where,tput_title,format_units());
2698 }
2699
2700 /* initialize a few counters */
2701
2702 nummessages = 0;
2703 bytes_xferd = 0;
2704 times_up = 0;
2705
2706 /* set-up the data buffer with the requested alignment and offset */
2707 temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
2708 if (temp_message_ptr == NULL) {
2709 printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
2710 exit(1);
2711 }
2712 send_message_ptr = (char *)(( (long)temp_message_ptr +
2713 (long) local_send_align - 1) &
2714 ~((long) local_send_align - 1));
2715 send_message_ptr = send_message_ptr + local_send_offset;
2716 send_message.maxlen = req_size;
2717 send_message.len = req_size;
2718 send_message.buf = send_message_ptr;
2719
2720 temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
2721 if (temp_message_ptr == NULL) {
2722 printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
2723 exit(1);
2724 }
2725 recv_message_ptr = (char *)(( (long)temp_message_ptr +
2726 (long) local_recv_align - 1) &
2727 ~((long) local_recv_align - 1));
2728 recv_message_ptr = recv_message_ptr + local_recv_offset;
2729 recv_message.maxlen = rsp_size;
2730 recv_message.len = 0;
2731 recv_message.buf = recv_message_ptr;
2732
2733 sctl_message.maxlen = BUFSIZ;
2734 sctl_message.len = 0;
2735 sctl_message.buf = sctl_data;
2736
2737 rctl_message.maxlen = BUFSIZ;
2738 rctl_message.len = 0;
2739 rctl_message.buf = rctl_data;
2740
2741 /* lets get ourselves a file descriptor */
2742
2743 send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
2744 if (send_descriptor < 0){
2745 perror("netperf: send_dlpi_cl_rr: dlpi cl rr send descriptor");
2746 exit(1);
2747 }
2748
2749 if (debug) {
2750 fprintf(where,"send_dlpi_cl_rr: send_descriptor obtained...\n");
2751 }
2752
2753 /* bind the sap to the descriptor and get the dlsap */
2754 dlsap_len = BUFSIZ;
2755 if (dl_bind(send_descriptor,
2756 dlpi_sap,
2757 DL_CLDLS,
2758 dlsap,
2759 &dlsap_len) != 0) {
2760 fprintf(where,"send_dlpi_cl_rr: bind failure\n");
2761 fflush(where);
2762 exit(1);
2763 }
2764
2765 /* Modify the local socket size. If the user has not requested that */
2766 /* the socket buffers be altered, we will try to find-out what their */
2767 /* values are. If we cannot touch the socket buffer in any way, we */
2768 /* will set the values to -1 to indicate that. The receive socket */
2769 /* must have enough space to hold addressing information so += a */
2770 /* sizeof struct sockaddr_in to it. */
2771
2772 /* this is actually nothing code, and should be replaced with the */
2773 /* alalagous calls in the STREAM test where the window size is set */
2774 /* with the HP DLPI Extension. raj 8/94 */
2775 #ifdef SO_SNDBUF
2776 if (lsw_size > 0) {
2777 if (debug > 1) {
2778 fprintf(where,"netperf: send_dlpi_cl_rr: local window size altered from system default...\n");
2779 fprintf(where," window: %d\n",lsw_size);
2780 }
2781 }
2782 if (lrw_size > 0) {
2783 if (debug > 1) {
2784 fprintf(where,"netperf: send_dlpi_cl_rr: remote window size altered from system default...\n");
2785 fprintf(where," remote: %d\n",lrw_size);
2786 }
2787 }
2788
2789
2790 /* Now, we will find-out what the size actually became, and report */
2791 /* that back to the user. If the call fails, we will just report a -1 */
2792 /* back to the initiator for the recv buffer size. */
2793
2794 if (debug) {
2795 fprintf(where,"netperf: send_dlpi_cl_rr: socket sizes determined...\n");
2796 fprintf(where," send: %d recv: %d\n",lsw_size,lrw_size);
2797 }
2798
2799 #else /* SO_SNDBUF */
2800
2801 lsw_size = -1;
2802 lrw_size = -1;
2803
2804 #endif /* SO_SNDBUF */
2805
2806 /* If the user has requested cpu utilization measurements, we must */
2807 /* calibrate the cpu(s). We will perform this task within the tests */
2808 /* themselves. If the user has specified the cpu rate, then */
2809 /* calibrate_local_cpu will return rather quickly as it will have */
2810 /* nothing to do. If local_cpu_rate is zero, then we will go through */
2811 /* all the "normal" calibration stuff and return the rate back. If */
2812 /* there is no idle counter in the kernel idle loop, the */
2813 /* local_cpu_rate will be set to -1. */
2814
2815 if (local_cpu_usage) {
2816 local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2817 }
2818
2819 /* Tell the remote end to do a listen. The server alters the socket */
2820 /* paramters on the other side at this point, hence the reason for */
2821 /* all the values being passed in the setup message. If the user did */
2822 /* not specify any of the parameters, they will be passed as 0, which */
2823 /* will indicate to the remote that no changes beyond the system's */
2824 /* default should be used. Alignment is the exception, it will */
2825 /* default to 8, which will be no alignment alterations. */
2826
2827 netperf_request.content.request_type = DO_DLPI_CL_RR;
2828 dlpi_cl_rr_request->recv_win_size = rrw_size;
2829 dlpi_cl_rr_request->send_win_size = rsw_size;
2830 dlpi_cl_rr_request->recv_alignment = remote_recv_align;
2831 dlpi_cl_rr_request->recv_offset = remote_recv_offset;
2832 dlpi_cl_rr_request->send_alignment = remote_send_align;
2833 dlpi_cl_rr_request->send_offset = remote_send_offset;
2834 dlpi_cl_rr_request->request_size = req_size;
2835 dlpi_cl_rr_request->response_size = rsp_size;
2836 dlpi_cl_rr_request->measure_cpu = remote_cpu_usage;
2837 dlpi_cl_rr_request->cpu_rate = remote_cpu_rate;
2838 dlpi_cl_rr_request->ppa = rem_ppa;
2839 dlpi_cl_rr_request->sap = dlpi_sap;
2840 dlpi_cl_rr_request->dev_name_len = strlen(rem_dlpi_device);
2841 strcpy(dlpi_cl_rr_request->dlpi_device,
2842 rem_dlpi_device);
2843
2844 #ifdef __alpha
2845
2846 /* ok - even on a DEC box, strings are strings. I din't really want */
2847 /* to ntohl the words of a string. since I don't want to teach the */
2848 /* send_ and recv_ _request and _response routines about the types, */
2849 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2850 /* solution would be to use XDR, but I am still leary of being able */
2851 /* to find XDR libs on all platforms I want running netperf. raj */
2852 {
2853 int *charword;
2854 int *initword;
2855 int *lastword;
2856
2857 initword = (int *) dlpi_cl_rr_request->dlpi_device;
2858 lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
2859
2860 for (charword = initword;
2861 charword < lastword;
2862 charword++) {
2863
2864 *charword = ntohl(*charword);
2865 }
2866 }
2867 #endif /* __alpha */
2868
2869 if (test_time) {
2870 dlpi_cl_rr_request->test_length = test_time;
2871 }
2872 else {
2873 dlpi_cl_rr_request->test_length = test_trans * -1;
2874 }
2875
2876 if (debug > 1) {
2877 fprintf(where,"netperf: send_dlpi_cl_rr: requesting DLPI CL request/response test\n");
2878 }
2879
2880 send_request();
2881
2882 /* The response from the remote will contain all of the relevant */
2883 /* socket parameters for this test type. We will put them back into */
2884 /* the variables here so they can be displayed if desired. The */
2885 /* remote will have calibrated CPU if necessary, and will have done */
2886 /* all the needed set-up we will have calibrated the cpu locally */
2887 /* before sending the request, and will grab the counter value right */
2888 /* after the connect returns. The remote will grab the counter right */
2889 /* after the accept call. This saves the hassle of extra messages */
2890 /* being sent for the tests. */
2891
2892 recv_response();
2893
2894 if (!netperf_response.content.serv_errno) {
2895 if (debug)
2896 fprintf(where,"remote listen done.\n");
2897 rrw_size = dlpi_cl_rr_response->recv_win_size;
2898 rsw_size = dlpi_cl_rr_response->send_win_size;
2899 remote_cpu_usage= dlpi_cl_rr_response->measure_cpu;
2900 remote_cpu_rate = dlpi_cl_rr_response->cpu_rate;
2901
2902 /* set-up the destination addressing control info */
2903 data_req->dl_primitive = DL_UNITDATA_REQ;
2904 bcopy((char *)(dlpi_cl_rr_response->station_addr),
2905 ((char *)data_req + sizeof(dl_unitdata_req_t)),
2906 dlpi_cl_rr_response->station_addr_len);
2907 data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
2908 data_req->dl_dest_addr_length = dlpi_cl_rr_response->station_addr_len;
2909 /* there is a dl_priority structure too, but I am ignoring it for */
2910 /* the time being. */
2911 sctl_message.len = sizeof(dl_unitdata_req_t) +
2912 data_req->dl_dest_addr_length;
2913 /* famous last words - some DLPI providers get unhappy if the
2914 priority stuff is not initialized. fix from Nicolas Thomas. */
2915 data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
2916 data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
2917
2918 }
2919 else {
2920 Set_errno(netperf_response.content.serv_errno);
2921 perror("netperf: remote error");
2922 exit(1);
2923 }
2924
2925 /* Data Socket set-up is finished. If there were problems, either the */
2926 /* connect would have failed, or the previous response would have */
2927 /* indicated a problem. I failed to see the value of the extra */
2928 /* message after the accept on the remote. If it failed, we'll see it */
2929 /* here. If it didn't, we might as well start pumping data. */
2930
2931 /* Set-up the test end conditions. For a request/response test, they */
2932 /* can be either time or transaction based. */
2933
2934 if (test_time) {
2935 /* The user wanted to end the test after a period of time. */
2936 times_up = 0;
2937 trans_remaining = 0;
2938 start_timer(test_time);
2939 }
2940 else {
2941 /* The tester wanted to send a number of bytes. */
2942 trans_remaining = test_bytes;
2943 times_up = 1;
2944 }
2945
2946 /* The cpu_start routine will grab the current time and possibly */
2947 /* value of the idle counter for later use in measuring cpu */
2948 /* utilization and/or service demand and thruput. */
2949
2950 cpu_start(local_cpu_usage);
2951
2952 /* We use an "OR" to control test execution. When the test is */
2953 /* controlled by time, the byte count check will always return false. */
2954 /* When the test is controlled by byte count, the time test will */
2955 /* always return false. When the test is finished, the whole */
2956 /* expression will go false and we will stop sending data. I think I */
2957 /* just arbitrarily decrement trans_remaining for the timed test, but */
2958 /* will not do that just yet... One other question is whether or not */
2959 /* the send buffer and the receive buffer should be the same buffer. */
2960 while ((!times_up) || (trans_remaining > 0)) {
2961 /* send the request */
2962 #ifdef WANT_INTERVALS
2963 gettimeofday(&send_time,&dummy_zone);
2964 #endif /* WANT_INTERVALS */
2965 if(putmsg(send_descriptor,
2966 &sctl_message,
2967 &send_message,
2968 0) != 0) {
2969 if (errno == EINTR) {
2970 /* We likely hit */
2971 /* test-end time. */
2972 break;
2973 }
2974 /* there is more we could do here, but it can wait */
2975 perror("send_dlpi_cl_rr: data send error");
2976 exit(1);
2977 }
2978
2979 /* receive the response. at some point, we will need to handle */
2980 /* sending responses which are greater than the datalink MTU. we */
2981 /* may also want to add some DLPI error checking, but for now we */
2982 /* will ignore that and just let errors stop the test with little */
2983 /* indication of what might actually be wrong. */
2984
2985 if((getmsg(send_descriptor,
2986 &rctl_message,
2987 &recv_message,
2988 &flags) != 0) ||
2989 (data_ind->dl_primitive != DL_UNITDATA_IND)) {
2990 if (errno == EINTR) {
2991 /* Again, we have likely hit test-end time */
2992 break;
2993 }
2994 fprintf(where,
2995 "send_dlpi_cl_rr: recv error: errno %d primitive 0x%x\n",
2996 errno,
2997 data_ind->dl_primitive);
2998 fflush(where);
2999 exit(1);
3000 }
3001 #ifdef WANT_INTERVALS
3002 gettimeofday(&recv_time,&dummy_zone);
3003
3004 /* now we do some arithmatic on the two timevals */
3005 if (recv_time.tv_usec < send_time.tv_usec) {
3006 /* we wrapped around a second */
3007 recv_time.tv_usec += 1000000;
3008 recv_time.tv_sec -= 1;
3009 }
3010
3011 /* and store it away */
3012 kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
3013 kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
3014
3015 /* at this point, we may wish to sleep for some period of */
3016 /* time, so we see how long that last transaction just took, */
3017 /* and sleep for the difference of that and the interval. We */
3018 /* will not sleep if the time would be less than a */
3019 /* millisecond. */
3020 if (interval_usecs > 0) {
3021 sleep_usecs = interval_usecs - kept_times[time_index];
3022 if (sleep_usecs > 1000) {
3023 /* we sleep */
3024 sleep_timeval.tv_sec = sleep_usecs / 1000000;
3025 sleep_timeval.tv_usec = sleep_usecs % 1000000;
3026 select(0,
3027 0,
3028 0,
3029 0,
3030 &sleep_timeval);
3031 }
3032 }
3033
3034 /* now up the time index */
3035 time_index = (time_index +1)%MAX_KEPT_TIMES;
3036 #endif /* WANT_INTERVALS */
3037 nummessages++;
3038 if (trans_remaining) {
3039 trans_remaining--;
3040 }
3041
3042 if (debug > 3) {
3043 fprintf(where,"Transaction %d completed\n",nummessages);
3044 fflush(where);
3045 }
3046
3047 }
3048
3049 /* this call will always give us the elapsed time for the test, and */
3050 /* will also store-away the necessaries for cpu utilization */
3051
3052 cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
3053 /* how long did we really run? */
3054
3055 /* Get the statistics from the remote end. The remote will have */
3056 /* calculated service demand and all those interesting things. If it */
3057 /* wasn't supposed to care, it will return obvious values. */
3058
3059 recv_response();
3060 if (!netperf_response.content.serv_errno) {
3061 if (debug)
3062 fprintf(where,"remote results obtained\n");
3063 }
3064 else {
3065 Set_errno(netperf_response.content.serv_errno);
3066 perror("netperf: remote error");
3067
3068 exit(1);
3069 }
3070
3071 /* We now calculate what our thruput was for the test. In the future, */
3072 /* we may want to include a calculation of the thruput measured by */
3073 /* the remote, but it should be the case that for a UDP stream test, */
3074 /* that the two numbers should be *very* close... We calculate */
3075 /* bytes_sent regardless of the way the test length was controlled. */
3076 /* If it was time, we needed to, and if it was by bytes, the user may */
3077 /* have specified a number of bytes that wasn't a multiple of the */
3078 /* send_size, so we really didn't send what he asked for ;-) We use */
3079
3080 bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
3081 thruput = calc_thruput(bytes_xferd);
3082
3083 if (local_cpu_usage || remote_cpu_usage) {
3084 /* We must now do a little math for service demand and cpu */
3085 /* utilization for the system(s) */
3086 /* Of course, some of the information might be bogus because */
3087 /* there was no idle counter in the kernel(s). We need to make */
3088 /* a note of this for the user's benefit...*/
3089 if (local_cpu_usage) {
3090 if (local_cpu_rate == 0.0) {
3091 fprintf(where,"WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
3092 fprintf(where,"Local CPU usage numbers based on process information only!\n");
3093 fflush(where);
3094 }
3095 local_cpu_utilization = calc_cpu_util(0.0);
3096 /* since calc_service demand is doing ms/Kunit we will */
3097 /* multiply the number of transaction by 1024 to get */
3098 /* "good" numbers */
3099 local_service_demand = calc_service_demand((double) nummessages*1024,
3100 0.0,
3101 0.0,
3102 0);
3103 }
3104 else {
3105 local_cpu_utilization = -1.0;
3106 local_service_demand = -1.0;
3107 }
3108
3109 if (remote_cpu_usage) {
3110 if (remote_cpu_rate == 0.0) {
3111 fprintf(where,"DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
3112 fprintf(where,"Remote CPU usage numbers based on process information only!\n");
3113 fflush(where);
3114 }
3115 remote_cpu_utilization = dlpi_cl_rr_result->cpu_util;
3116 /* since calc_service demand is doing ms/Kunit we will */
3117 /* multiply the number of transaction by 1024 to get */
3118 /* "good" numbers */
3119 remote_service_demand = calc_service_demand((double) nummessages*1024,
3120 0.0,
3121 remote_cpu_utilization,
3122 dlpi_cl_rr_result->num_cpus);
3123 }
3124 else {
3125 remote_cpu_utilization = -1.0;
3126 remote_service_demand = -1.0;
3127 }
3128
3129 /* We are now ready to print all the information. If the user */
3130 /* has specified zero-level verbosity, we will just print the */
3131 /* local service demand, or the remote service demand. If the */
3132 /* user has requested verbosity level 1, he will get the basic */
3133 /* "streamperf" numbers. If the user has specified a verbosity */
3134 /* of greater than 1, we will display a veritable plethora of */
3135 /* background information from outside of this block as it it */
3136 /* not cpu_measurement specific... */
3137
3138 switch (verbosity) {
3139 case 0:
3140 if (local_cpu_usage) {
3141 fprintf(where,
3142 cpu_fmt_0,
3143 local_service_demand);
3144 }
3145 else {
3146 fprintf(where,
3147 cpu_fmt_0,
3148 remote_service_demand);
3149 }
3150 break;
3151 case 1:
3152 case 2:
3153 fprintf(where,
3154 cpu_fmt_1_line_1, /* the format string */
3155 lsw_size, /* local sendbuf size */
3156 lrw_size,
3157 req_size, /* how large were the requests */
3158 rsp_size, /* guess */
3159 elapsed_time, /* how long was the test */
3160 nummessages/elapsed_time,
3161 local_cpu_utilization, /* local cpu */
3162 remote_cpu_utilization, /* remote cpu */
3163 local_service_demand, /* local service demand */
3164 remote_service_demand); /* remote service demand */
3165 fprintf(where,
3166 cpu_fmt_1_line_2,
3167 rsw_size,
3168 rrw_size);
3169 break;
3170 }
3171 }
3172 else {
3173 /* The tester did not wish to measure service demand. */
3174 switch (verbosity) {
3175 case 0:
3176 fprintf(where,
3177 tput_fmt_0,
3178 nummessages/elapsed_time);
3179 break;
3180 case 1:
3181 case 2:
3182 fprintf(where,
3183 tput_fmt_1_line_1, /* the format string */
3184 lsw_size,
3185 lrw_size,
3186 req_size, /* how large were the requests */
3187 rsp_size, /* how large were the responses */
3188 elapsed_time, /* how long did it take */
3189 nummessages/elapsed_time);
3190 fprintf(where,
3191 tput_fmt_1_line_2,
3192 rsw_size, /* remote recvbuf size */
3193 rrw_size);
3194
3195 break;
3196 }
3197 }
3198
3199 /* it would be a good thing to include information about some of the */
3200 /* other parameters that may have been set for this test, but at the */
3201 /* moment, I do not wish to figure-out all the formatting, so I will */
3202 /* just put this comment here to help remind me that it is something */
3203 /* that should be done at a later time. */
3204
3205 if (verbosity > 1) {
3206 /* The user wanted to know it all, so we will give it to him. */
3207 /* This information will include as much as we can find about */
3208 /* UDP statistics, the alignments of the sends and receives */
3209 /* and all that sort of rot... */
3210
3211 #ifdef WANT_INTERVALS
3212 kept_times[MAX_KEPT_TIMES] = 0;
3213 time_index = 0;
3214 while (time_index < MAX_KEPT_TIMES) {
3215 if (kept_times[time_index] > 0) {
3216 total_times += kept_times[time_index];
3217 }
3218 else
3219 unused_buckets++;
3220 time_index += 1;
3221 }
3222 total_times /= (MAX_KEPT_TIMES-unused_buckets);
3223 fprintf(where,
3224 "Average response time %d usecs\n",
3225 total_times);
3226 #endif
3227 }
3228 }
3229
3230 int
recv_dlpi_cl_rr()3231 recv_dlpi_cl_rr()
3232 {
3233
3234 char *message;
3235 int data_descriptor;
3236 int flags = 0;
3237 int measure_cpu;
3238
3239 char *recv_message_ptr;
3240 char *send_message_ptr;
3241 char sctl_data[BUFSIZ];
3242 char rctl_data[BUFSIZ];
3243 char dlsap[BUFSIZ];
3244 struct strbuf send_message;
3245 struct strbuf recv_message;
3246 struct strbuf sctl_message;
3247 struct strbuf rctl_message;
3248
3249 /* these are to make reading some of the DLPI control messages easier */
3250 dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
3251 dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
3252 dl_uderror_ind_t *uder_ind = (dl_uderror_ind_t *)rctl_data;
3253
3254 int trans_received;
3255 int trans_remaining;
3256 float elapsed_time;
3257
3258 struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request;
3259 struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response;
3260 struct dlpi_cl_rr_results_struct *dlpi_cl_rr_results;
3261
3262 dlpi_cl_rr_request =
3263 (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
3264 dlpi_cl_rr_response =
3265 (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
3266 dlpi_cl_rr_results =
3267 (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
3268
3269 if (debug) {
3270 fprintf(where,"netserver: recv_dlpi_cl_rr: entered...\n");
3271 fflush(where);
3272 }
3273
3274 /* We want to set-up the listen descriptor with all the desired */
3275 /* parameters and then let the initiator know that all is ready. If */
3276 /* socket size defaults are to be used, then the initiator will have */
3277 /* sent us 0's. If the descriptor sizes cannot be changed, then we will */
3278 /* send-back what they are. If that information cannot be determined, */
3279 /* then we send-back -1's for the sizes. If things go wrong for any */
3280 /* reason, we will drop back ten yards and punt. */
3281
3282 /* If anything goes wrong, we want the remote to know about it. It */
3283 /* would be best if the error that the remote reports to the user is */
3284 /* the actual error we encountered, rather than some bogus unexpected */
3285 /* response type message. */
3286
3287 if (debug) {
3288 fprintf(where,"recv_dlpi_cl_rr: setting the response type...\n");
3289 fflush(where);
3290 }
3291
3292 netperf_response.content.response_type = DLPI_CL_RR_RESPONSE;
3293
3294 if (debug) {
3295 fprintf(where,"recv_dlpi_cl_rr: the response type is set...\n");
3296 fflush(where);
3297 }
3298
3299 /* set-up the data buffer with the requested alignment and offset */
3300 message = (char *)malloc(DATABUFFERLEN);
3301 if (message == NULL) {
3302 printf("malloc(%d) failed!\n", DATABUFFERLEN);
3303 exit(1);
3304 }
3305
3306 /* We now alter the message_ptr variables to be at the desired */
3307 /* alignments with the desired offsets. */
3308
3309 if (debug) {
3310 fprintf(where,
3311 "recv_dlpi_cl_rr: requested recv alignment of %d offset %d\n",
3312 dlpi_cl_rr_request->recv_alignment,
3313 dlpi_cl_rr_request->recv_offset);
3314 fprintf(where,
3315 "recv_dlpi_cl_rr: requested send alignment of %d offset %d\n",
3316 dlpi_cl_rr_request->send_alignment,
3317 dlpi_cl_rr_request->send_offset);
3318 fflush(where);
3319 }
3320
3321 recv_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->recv_alignment, dlpi_cl_rr_request->recv_offset);
3322 recv_message.maxlen = dlpi_cl_rr_request->request_size;
3323 recv_message.len = 0;
3324 recv_message.buf = recv_message_ptr;
3325
3326 send_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->send_alignment, dlpi_cl_rr_request->send_offset);
3327 send_message.maxlen = dlpi_cl_rr_request->response_size;
3328 send_message.len = dlpi_cl_rr_request->response_size;
3329 send_message.buf = send_message_ptr;
3330
3331 sctl_message.maxlen = BUFSIZ;
3332 sctl_message.len = 0;
3333 sctl_message.buf = sctl_data;
3334
3335 rctl_message.maxlen = BUFSIZ;
3336 rctl_message.len = 0;
3337 rctl_message.buf = rctl_data;
3338
3339 if (debug) {
3340 fprintf(where,"recv_dlpi_cl_rr: receive alignment and offset set...\n");
3341 fprintf(where,"recv_dlpi_cl_rr: grabbing a socket...\n");
3342 fflush(where);
3343 }
3344
3345
3346 #ifdef __alpha
3347
3348 /* ok - even on a DEC box, strings are strings. I din't really want */
3349 /* to ntohl the words of a string. since I don't want to teach the */
3350 /* send_ and recv_ _request and _response routines about the types, */
3351 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3352 /* solution would be to use XDR, but I am still leary of being able */
3353 /* to find XDR libs on all platforms I want running netperf. raj */
3354 {
3355 int *charword;
3356 int *initword;
3357 int *lastword;
3358
3359 initword = (int *) dlpi_cl_rr_request->dlpi_device;
3360 lastword = initword + ((dlpi_cl_rr_request->dev_name_len + 3) / 4);
3361
3362 for (charword = initword;
3363 charword < lastword;
3364 charword++) {
3365
3366 *charword = htonl(*charword);
3367 }
3368 }
3369 #endif /* __alpha */
3370
3371 data_descriptor = dl_open(dlpi_cl_rr_request->dlpi_device,
3372 dlpi_cl_rr_request->ppa);
3373 if (data_descriptor < 0) {
3374 netperf_response.content.serv_errno = errno;
3375 send_response();
3376 exit(1);
3377 }
3378
3379
3380 /* The initiator may have wished-us to modify the window */
3381 /* sizes. We should give it a shot. If he didn't ask us to change the */
3382 /* sizes, we should let him know what sizes were in use at this end. */
3383 /* If none of this code is compiled-in, then we will tell the */
3384 /* initiator that we were unable to play with the sizes by */
3385 /* setting the size in the response to -1. */
3386
3387 #ifdef DL_HP_SET_LOCAL_WIN_REQ
3388
3389 if (dlpi_cl_rr_request->recv_win_size) {
3390 }
3391
3392 if (dlpi_cl_rr_request->send_win_size) {
3393 }
3394
3395 /* Now, we will find-out what the sizes actually became, and report */
3396 /* them back to the user. If the calls fail, we will just report a -1 */
3397 /* back to the initiator for the buffer size. */
3398
3399 #else /* the system won't let us play with the buffers */
3400
3401 dlpi_cl_rr_response->recv_win_size = -1;
3402 dlpi_cl_rr_response->send_win_size = -1;
3403
3404 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
3405
3406 /* bind the sap and retrieve the dlsap assigned by the system */
3407 dlpi_cl_rr_response->station_addr_len = 14; /* arbitrary */
3408 if (dl_bind(data_descriptor,
3409 dlpi_cl_rr_request->sap,
3410 DL_CLDLS,
3411 (char *)dlpi_cl_rr_response->station_addr,
3412 &dlpi_cl_rr_response->station_addr_len) != 0) {
3413 fprintf(where,"send_dlpi_cl_rr: bind failure\n");
3414 fflush(where);
3415 exit(1);
3416 }
3417
3418 netperf_response.content.serv_errno = 0;
3419
3420 /* But wait, there's more. If the initiator wanted cpu measurements, */
3421 /* then we must call the calibrate routine, which will return the max */
3422 /* rate back to the initiator. If the CPU was not to be measured, or */
3423 /* something went wrong with the calibration, we will return a 0.0 to */
3424 /* the initiator. */
3425
3426 dlpi_cl_rr_response->cpu_rate = 0.0; /* assume no cpu */
3427 if (dlpi_cl_rr_request->measure_cpu) {
3428 dlpi_cl_rr_response->measure_cpu = 1;
3429 dlpi_cl_rr_response->cpu_rate = calibrate_local_cpu(dlpi_cl_rr_request->cpu_rate);
3430 }
3431
3432 send_response();
3433
3434 /* Now it's time to start receiving data on the connection. We will */
3435 /* first grab the apropriate counters and then start receiving. */
3436
3437 cpu_start(dlpi_cl_rr_request->measure_cpu);
3438
3439 if (dlpi_cl_rr_request->test_length > 0) {
3440 times_up = 0;
3441 trans_remaining = 0;
3442 start_timer(dlpi_cl_rr_request->test_length + PAD_TIME);
3443 }
3444 else {
3445 times_up = 1;
3446 trans_remaining = dlpi_cl_rr_request->test_length * -1;
3447 }
3448
3449 while ((!times_up) || (trans_remaining > 0)) {
3450
3451 /* receive the request from the other side. at some point we need */
3452 /* to handle "logical" requests and responses which are larger */
3453 /* than the data link MTU */
3454
3455 if((getmsg(data_descriptor,
3456 &rctl_message,
3457 &recv_message,
3458 &flags) != 0) ||
3459 (data_ind->dl_primitive != DL_UNITDATA_IND)) {
3460 if (errno == EINTR) {
3461 /* Again, we have likely hit test-end time */
3462 break;
3463 }
3464 fprintf(where,
3465 "dlpi_recv_cl_rr: getmsg failure: errno %d primitive 0x%x\n",
3466 errno,
3467 data_ind->dl_primitive);
3468 fprintf(where,
3469 " recevied %u transactions\n",
3470 trans_received);
3471 fflush(where);
3472 netperf_response.content.serv_errno = 995;
3473 send_response();
3474 exit(1);
3475 }
3476
3477 /* Now, send the response to the remote. first copy the dlsap */
3478 /* information from the receive to the sending control message */
3479
3480 data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
3481 bcopy((char *)data_ind + data_ind->dl_src_addr_offset,
3482 (char *)data_req + data_req->dl_dest_addr_offset,
3483 data_ind->dl_src_addr_length);
3484 data_req->dl_dest_addr_length = data_ind->dl_src_addr_length;
3485 data_req->dl_primitive = DL_UNITDATA_REQ;
3486 /* be sure to initialize the priority fields. fix from Nicholas
3487 Thomas */
3488 data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
3489 data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
3490
3491 sctl_message.len = sizeof(dl_unitdata_req_t) +
3492 data_ind->dl_src_addr_length;
3493 if(putmsg(data_descriptor,
3494 &sctl_message,
3495 &send_message,
3496 0) != 0) {
3497 if (errno == EINTR) {
3498 /* We likely hit */
3499 /* test-end time. */
3500 break;
3501 }
3502 /* there is more we could do here, but it can wait */
3503 fprintf(where,
3504 "dlpi_recv_cl_rr: putmsg failure: errno %d\n",
3505 errno);
3506 fflush(where);
3507 netperf_response.content.serv_errno = 993;
3508 send_response();
3509 exit(1);
3510 }
3511
3512 trans_received++;
3513 if (trans_remaining) {
3514 trans_remaining--;
3515 }
3516
3517 if (debug) {
3518 fprintf(where,
3519 "recv_dlpi_cl_rr: Transaction %d complete.\n",
3520 trans_received);
3521 fflush(where);
3522 }
3523
3524 }
3525
3526
3527 /* The loop now exits due to timeout or transaction count being */
3528 /* reached */
3529
3530 cpu_stop(dlpi_cl_rr_request->measure_cpu,&elapsed_time);
3531
3532 if (times_up) {
3533 /* we ended the test by time, which was at least 2 seconds */
3534 /* longer than we wanted to run. so, we want to subtract */
3535 /* PAD_TIME from the elapsed_time. */
3536 elapsed_time -= PAD_TIME;
3537 }
3538 /* send the results to the sender */
3539
3540 if (debug) {
3541 fprintf(where,
3542 "recv_dlpi_cl_rr: got %d transactions\n",
3543 trans_received);
3544 fflush(where);
3545 }
3546
3547 dlpi_cl_rr_results->bytes_received = (trans_received *
3548 (dlpi_cl_rr_request->request_size +
3549 dlpi_cl_rr_request->response_size));
3550 dlpi_cl_rr_results->trans_received = trans_received;
3551 dlpi_cl_rr_results->elapsed_time = elapsed_time;
3552 if (dlpi_cl_rr_request->measure_cpu) {
3553 dlpi_cl_rr_results->cpu_util = calc_cpu_util(elapsed_time);
3554 }
3555
3556 if (debug) {
3557 fprintf(where,
3558 "recv_dlpi_cl_rr: test complete, sending results.\n");
3559 fflush(where);
3560 }
3561
3562 send_response();
3563
3564 }
3565
3566 int
recv_dlpi_co_rr()3567 recv_dlpi_co_rr()
3568 {
3569
3570 char *message;
3571 SOCKET s_listen,data_descriptor;
3572
3573 int measure_cpu;
3574
3575 int flags = 0;
3576 char *recv_message_ptr;
3577 char *send_message_ptr;
3578 struct strbuf send_message;
3579 struct strbuf recv_message;
3580
3581 int trans_received;
3582 int trans_remaining;
3583 int request_bytes_remaining;
3584 int timed_out = 0;
3585 float elapsed_time;
3586
3587 struct dlpi_co_rr_request_struct *dlpi_co_rr_request;
3588 struct dlpi_co_rr_response_struct *dlpi_co_rr_response;
3589 struct dlpi_co_rr_results_struct *dlpi_co_rr_results;
3590
3591 dlpi_co_rr_request = (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
3592 dlpi_co_rr_response = (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
3593 dlpi_co_rr_results = (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
3594
3595 if (debug) {
3596 fprintf(where,"netserver: recv_dlpi_co_rr: entered...\n");
3597 fflush(where);
3598 }
3599
3600 /* We want to set-up the listen socket with all the desired */
3601 /* parameters and then let the initiator know that all is ready. If */
3602 /* socket size defaults are to be used, then the initiator will have */
3603 /* sent us 0's. If the socket sizes cannot be changed, then we will */
3604 /* send-back what they are. If that information cannot be determined, */
3605 /* then we send-back -1's for the sizes. If things go wrong for any */
3606 /* reason, we will drop back ten yards and punt. */
3607
3608 /* If anything goes wrong, we want the remote to know about it. It */
3609 /* would be best if the error that the remote reports to the user is */
3610 /* the actual error we encountered, rather than some bogus unexpected */
3611 /* response type message. */
3612
3613 if (debug) {
3614 fprintf(where,"recv_dlpi_co_rr: setting the response type...\n");
3615 fflush(where);
3616 }
3617
3618 netperf_response.content.response_type = DLPI_CO_RR_RESPONSE;
3619
3620 if (debug) {
3621 fprintf(where,"recv_dlpi_co_rr: the response type is set...\n");
3622 fflush(where);
3623 }
3624
3625 /* set-up the data buffer with the requested alignment and offset */
3626 message = (char *)malloc(DATABUFFERLEN);
3627 if (message == NULL) {
3628 printf("malloc(%d) failed!\n", DATABUFFERLEN);
3629 exit(1);
3630 }
3631
3632 /* We now alter the message_ptr variables to be at the desired */
3633 /* alignments with the desired offsets. */
3634
3635 if (debug) {
3636 fprintf(where,
3637 "recv_dlpi_co_rr: requested recv alignment of %d offset %d\n",
3638 dlpi_co_rr_request->recv_alignment,
3639 dlpi_co_rr_request->recv_offset);
3640 fprintf(where,
3641 "recv_dlpi_co_rr: requested send alignment of %d offset %d\n",
3642 dlpi_co_rr_request->send_alignment,
3643 dlpi_co_rr_request->send_offset);
3644 fflush(where);
3645 }
3646
3647 recv_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->recv_alignment, dlpi_co_rr_request->recv_offset);
3648 recv_message.maxlen = dlpi_co_rr_request->request_size;
3649 recv_message.len = 0;
3650 recv_message.buf = recv_message_ptr;
3651
3652 send_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->send_alignment, dlpi_co_rr_request->send_offset);
3653 send_message.maxlen = dlpi_co_rr_request->response_size;
3654 send_message.len = dlpi_co_rr_request->response_size;
3655 send_message.buf = send_message_ptr;
3656
3657 if (debug) {
3658 fprintf(where,"recv_dlpi_co_rr: receive alignment and offset set...\n");
3659 fprintf(where,"recv_dlpi_co_rr: send_message.buf %x .len %d .maxlen %d\n",
3660 send_message.buf,send_message.len,send_message.maxlen);
3661 fprintf(where,"recv_dlpi_co_rr: recv_message.buf %x .len %d .maxlen %d\n",
3662 recv_message.buf,recv_message.len,recv_message.maxlen);
3663 fflush(where);
3664 }
3665
3666 /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3667 /* can put in OUR values !-) At some point, we may want to nail this */
3668 /* socket to a particular network-level address, but for now, */
3669 /* INADDR_ANY should be just fine. */
3670
3671 /* Grab a socket to listen on, and then listen on it. */
3672
3673 if (debug) {
3674 fprintf(where,"recv_dlpi_co_rr: grabbing a socket...\n");
3675 fflush(where);
3676 }
3677
3678 /* lets grab a file descriptor for a particular link */
3679
3680 #ifdef __alpha
3681
3682 /* ok - even on a DEC box, strings are strings. I din't really want */
3683 /* to ntohl the words of a string. since I don't want to teach the */
3684 /* send_ and recv_ _request and _response routines about the types, */
3685 /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3686 /* solution would be to use XDR, but I am still leary of being able */
3687 /* to find XDR libs on all platforms I want running netperf. raj */
3688 {
3689 int *charword;
3690 int *initword;
3691 int *lastword;
3692
3693 initword = (int *) dlpi_co_rr_request->dlpi_device;
3694 lastword = initword + ((dlpi_co_rr_request->dev_name_len + 3) / 4);
3695
3696 for (charword = initword;
3697 charword < lastword;
3698 charword++) {
3699
3700 *charword = htonl(*charword);
3701 }
3702 }
3703 #endif /* __alpha */
3704
3705 if ((data_descriptor = dl_open(dlpi_co_rr_request->dlpi_device,
3706 dlpi_co_rr_request->ppa)) < 0) {
3707 netperf_response.content.serv_errno = errno;
3708 send_response();
3709 exit(1);
3710 }
3711
3712 /* bind the file descriptor to a sap and get the resultant dlsap */
3713 dlpi_co_rr_response->station_addr_len = 14; /*arbitrary needs fixing */
3714 if (dl_bind(data_descriptor,
3715 dlpi_co_rr_request->sap,
3716 DL_CODLS,
3717 (char *)dlpi_co_rr_response->station_addr,
3718 &dlpi_co_rr_response->station_addr_len) != 0) {
3719 netperf_response.content.serv_errno = errno;
3720 send_response();
3721 exit(1);
3722 }
3723
3724 /* The initiator may have wished-us to modify the socket buffer */
3725 /* sizes. We should give it a shot. If he didn't ask us to change the */
3726 /* sizes, we should let him know what sizes were in use at this end. */
3727 /* If none of this code is compiled-in, then we will tell the */
3728 /* initiator that we were unable to play with the socket buffer by */
3729 /* setting the size in the response to -1. */
3730
3731 #ifdef DL_HP_SET_LOCAL_WIN_REQ
3732
3733 if (dlpi_co_rr_request->recv_win_size) {
3734 /* SMOP */
3735 }
3736
3737 if (dlpi_co_rr_request->send_win_size) {
3738 /* SMOP */
3739 }
3740
3741 /* Now, we will find-out what the sizes actually became, and report */
3742 /* them back to the user. If the calls fail, we will just report a -1 */
3743 /* back to the initiator for the buffer size. */
3744
3745 #else /* the system won't let us play with the buffers */
3746
3747 dlpi_co_rr_response->recv_win_size = -1;
3748 dlpi_co_rr_response->send_win_size = -1;
3749
3750 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
3751
3752 /* we may have been requested to enable the copy avoidance features. */
3753 /* can we actually do this with DLPI, the world wonders */
3754
3755 if (dlpi_co_rr_request->so_rcvavoid) {
3756 #ifdef SO_RCV_COPYAVOID
3757 dlpi_co_rr_response->so_rcvavoid = 0;
3758 #else
3759 /* it wasn't compiled in... */
3760 dlpi_co_rr_response->so_rcvavoid = 0;
3761 #endif
3762 }
3763
3764 if (dlpi_co_rr_request->so_sndavoid) {
3765 #ifdef SO_SND_COPYAVOID
3766 dlpi_co_rr_response->so_sndavoid = 0;
3767 #else
3768 /* it wasn't compiled in... */
3769 dlpi_co_rr_response->so_sndavoid = 0;
3770 #endif
3771 }
3772
3773 netperf_response.content.serv_errno = 0;
3774
3775 /* But wait, there's more. If the initiator wanted cpu measurements, */
3776 /* then we must call the calibrate routine, which will return the max */
3777 /* rate back to the initiator. If the CPU was not to be measured, or */
3778 /* something went wrong with the calibration, we will return a 0.0 to */
3779 /* the initiator. */
3780
3781 dlpi_co_rr_response->cpu_rate = 0.0; /* assume no cpu */
3782 if (dlpi_co_rr_request->measure_cpu) {
3783 dlpi_co_rr_response->measure_cpu = 1;
3784 dlpi_co_rr_response->cpu_rate = calibrate_local_cpu(dlpi_co_rr_request->cpu_rate);
3785 }
3786
3787 send_response();
3788
3789 /* accept a connection on this file descriptor. at some point, */
3790 /* dl_accept will "do the right thing" with the last two parms, but */
3791 /* for now it ignores them, so we will pass zeros. */
3792
3793 if(dl_accept(data_descriptor, 0, 0) != 0) {
3794 fprintf(where,
3795 "recv_dlpi_co_rr: error in accept, errno %d\n",
3796 errno);
3797 fflush(where);
3798 netperf_response.content.serv_errno = errno;
3799 send_response();
3800 exit(1);
3801 }
3802
3803 if (debug) {
3804 fprintf(where,
3805 "recv_dlpi_co_rr: accept completes on the data connection.\n");
3806 fflush(where);
3807 }
3808
3809 /* Now it's time to start receiving data on the connection. We will */
3810 /* first grab the apropriate counters and then start grabbing. */
3811
3812 cpu_start(dlpi_co_rr_request->measure_cpu);
3813
3814 /* The loop will exit when the sender does a shutdown, which will */
3815 /* return a length of zero */
3816
3817 if (dlpi_co_rr_request->test_length > 0) {
3818 times_up = 0;
3819 trans_remaining = 0;
3820 start_timer(dlpi_co_rr_request->test_length + PAD_TIME);
3821 }
3822 else {
3823 times_up = 1;
3824 trans_remaining = dlpi_co_rr_request->test_length * -1;
3825 }
3826
3827 while ((!times_up) || (trans_remaining > 0)) {
3828 request_bytes_remaining = dlpi_co_rr_request->request_size;
3829
3830 /* receive the request from the other side. there needs to be some */
3831 /* more login in place for handling messages larger than link mtu, */
3832 /* but that can wait for later */
3833 while(request_bytes_remaining > 0) {
3834 if((getmsg(data_descriptor,
3835 0,
3836 &recv_message,
3837 &flags)) < 0) {
3838 if (errno == EINTR) {
3839 /* the timer popped */
3840 timed_out = 1;
3841 break;
3842 }
3843
3844 if (debug) {
3845 fprintf(where,"failed getmsg call errno %d\n",errno);
3846 fprintf(where,"recv_message.len %d\n",recv_message.len);
3847 fprintf(where,"send_message.len %d\n",send_message.len);
3848 fflush(where);
3849 }
3850
3851 netperf_response.content.serv_errno = errno;
3852 send_response();
3853 exit(1);
3854 }
3855 else {
3856 request_bytes_remaining -= recv_message.len;
3857 }
3858 }
3859
3860 if (timed_out) {
3861 /* we hit the end of the test based on time - lets bail out of */
3862 /* here now... */
3863 break;
3864 }
3865
3866 if (debug) {
3867 fprintf(where,"recv_message.len %d\n",recv_message.len);
3868 fprintf(where,"send_message.len %d\n",send_message.len);
3869 fflush(where);
3870 }
3871
3872 /* Now, send the response to the remote */
3873 if((putmsg(data_descriptor,
3874 0,
3875 &send_message,
3876 0)) != 0) {
3877 if (errno == EINTR) {
3878 /* the test timer has popped */
3879 timed_out = 1;
3880 break;
3881 }
3882 netperf_response.content.serv_errno = 994;
3883 send_response();
3884 exit(1);
3885 }
3886
3887 trans_received++;
3888 if (trans_remaining) {
3889 trans_remaining--;
3890 }
3891
3892 if (debug) {
3893 fprintf(where,
3894 "recv_dlpi_co_rr: Transaction %d complete\n",
3895 trans_received);
3896 fflush(where);
3897 }
3898 }
3899
3900
3901 /* The loop now exits due to timeout or transaction count being */
3902 /* reached */
3903
3904 cpu_stop(dlpi_co_rr_request->measure_cpu,&elapsed_time);
3905
3906 if (timed_out) {
3907 /* we ended the test by time, which was at least 2 seconds */
3908 /* longer than we wanted to run. so, we want to subtract */
3909 /* PAD_TIME from the elapsed_time. */
3910 elapsed_time -= PAD_TIME;
3911 }
3912 /* send the results to the sender */
3913
3914 if (debug) {
3915 fprintf(where,
3916 "recv_dlpi_co_rr: got %d transactions\n",
3917 trans_received);
3918 fflush(where);
3919 }
3920
3921 dlpi_co_rr_results->bytes_received = (trans_received *
3922 (dlpi_co_rr_request->request_size +
3923 dlpi_co_rr_request->response_size));
3924 dlpi_co_rr_results->trans_received = trans_received;
3925 dlpi_co_rr_results->elapsed_time = elapsed_time;
3926 if (dlpi_co_rr_request->measure_cpu) {
3927 dlpi_co_rr_results->cpu_util = calc_cpu_util(elapsed_time);
3928 }
3929
3930 if (debug) {
3931 fprintf(where,
3932 "recv_dlpi_co_rr: test complete, sending results.\n");
3933 fflush(where);
3934 }
3935
3936 send_response();
3937
3938 }
3939
3940 /* this routine will display the usage string for the DLPI tests */
3941 void
print_dlpi_usage()3942 print_dlpi_usage()
3943
3944 {
3945 fwrite(dlpi_usage, sizeof(char), strlen(dlpi_usage), stdout);
3946 }
3947
3948
3949 /* this routine will scan the command line for DLPI test arguments */
3950 void
scan_dlpi_args(int argc,char * argv[])3951 scan_dlpi_args(int argc, char *argv[])
3952 {
3953 extern int optind, opterrs; /* index of first unused arg */
3954 extern char *optarg; /* pointer to option string */
3955
3956 int c;
3957
3958 char arg1[BUFSIZ], /* argument holders */
3959 arg2[BUFSIZ];
3960
3961 if (no_control) {
3962 fprintf(where,
3963 "The DLPI tests do not know how to run with no control connection\n");
3964 exit(-1);
3965 }
3966
3967 /* Go through all the command line arguments and break them */
3968 /* out. For those options that take two parms, specifying only */
3969 /* the first will set both to that value. Specifying only the */
3970 /* second will leave the first untouched. To change only the */
3971 /* first, use the form first, (see the routine break_args.. */
3972
3973 #define DLPI_ARGS "D:hM:m:p:r:s:W:w:"
3974
3975 while ((c= getopt(argc, argv, DLPI_ARGS)) != EOF) {
3976 switch (c) {
3977 case '?':
3978 case 'h':
3979 print_dlpi_usage();
3980 exit(1);
3981 case 'D':
3982 /* set the dlpi device file name(s) */
3983 break_args(optarg,arg1,arg2);
3984 if (arg1[0])
3985 strcpy(loc_dlpi_device,arg1);
3986 if (arg2[0])
3987 strcpy(rem_dlpi_device,arg2);
3988 break;
3989 case 'm':
3990 /* set the send size */
3991 send_size = atoi(optarg);
3992 break;
3993 case 'M':
3994 /* set the recv size */
3995 recv_size = atoi(optarg);
3996 break;
3997 case 'p':
3998 /* set the local/remote ppa */
3999 break_args(optarg,arg1,arg2);
4000 if (arg1[0])
4001 loc_ppa = atoi(arg1);
4002 if (arg2[0])
4003 rem_ppa = atoi(arg2);
4004 break;
4005 case 'r':
4006 /* set the request/response sizes */
4007 break_args(optarg,arg1,arg2);
4008 if (arg1[0])
4009 req_size = atoi(arg1);
4010 if (arg2[0])
4011 rsp_size = atoi(arg2);
4012 break;
4013 case 's':
4014 /* set the 802.2 sap for the test */
4015 dlpi_sap = atoi(optarg);
4016 break;
4017 case 'w':
4018 /* set local window sizes */
4019 break_args(optarg,arg1,arg2);
4020 if (arg1[0])
4021 lsw_size = atoi(arg1);
4022 if (arg2[0])
4023 lrw_size = atoi(arg2);
4024 break;
4025 case 'W':
4026 /* set remote window sizes */
4027 break_args(optarg,arg1,arg2);
4028 if (arg1[0])
4029 rsw_size = atoi(arg1);
4030 if (arg2[0])
4031 rrw_size = atoi(arg2);
4032 break;
4033 };
4034 }
4035 }
4036
4037
4038 #endif /* WANT_DLPI */
4039