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
24char	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
54static 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
64int
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
70char loc_dlpi_device[32] = "/dev/dlpi";
71char rem_dlpi_device[32] = "/dev/dlpi";
72
73char dlpi_usage[] = "\n\
74Usage: netperf [global options] -- [test options] \n\
75\n\
76CO/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\
88For those options taking two parms, at least one must be specified;\n\
89specifying one value without a comma will set both parms to that\n\
90value, specifying a value with a leading comma will set just the second\n\
91parm, a value with a trailing comma will set just the first. To set\n\
92each parm to unique values, specify both and separate them with a\n\
93comma.\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
102void
103send_dlpi_co_stream()
104{
105
106  char *tput_title = "\
107Recv   Send    Send                          \n\
108Window Window  Message  Elapsed              \n\
109Size   Size    Size     Time     Throughput  \n\
110frames 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 = "\
119Recv   Send    Send                          Utilization    Service Demand\n\
120Window Window  Message  Elapsed              Send   Recv    Send    Recv\n\
121Size   Size    Size     Time     Throughput  local  remote  local   remote\n\
122frames 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\
131Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
132Local  Remote  Local  Remote  Xfered   Per                 Per\n\
133Send   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
687int
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
995int 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
1577void
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\
1587Size    Size     Time         Okay Errors   Throughput\n\
1588frames  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\
1600Size    Size     Time         Okay Errors   Throughput   Util    Demand\n\
1601frames  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
2060int
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
2347int send_dlpi_cl_rr(char remote_host[])
2348{
2349
2350  char *tput_title = "\
2351Local /Remote\n\
2352Window Size   Request  Resp.   Elapsed  Trans.\n\
2353Send   Recv   Size     Size    Time     Rate         \n\
2354frames 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 = "\
2365Local /Remote\n\
2366Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
2367Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
2368frames 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 = "\
2380Alignment      Offset\n\
2381Local  Remote  Local  Remote\n\
2382Send   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
2990int
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  }
3204else {
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
3326int
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  }
3582else {
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 */
3701void
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 */
3710void
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