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