NetBSD-5.0.2/dist/iscsi/src/usocktest.c

Compare this file to the similar file:
Show the results in this format:

/*
 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or
 * using the software you agree to this license. If you do not agree to this license, do not download, install,
 * copy or use the software. 
 *
 * Intel License Agreement 
 *
 * Copyright (c) 2000, Intel Corporation
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met: 
 *
 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *  following disclaimer. 
 *
 * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *  following disclaimer in the documentation and/or other materials provided with the distribution. 
 *
 * -The name of Intel Corporation may not be used to endorse or promote products derived from this software
 *  without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE. 
 */
#include "config.h"

#define EXTERN

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include "iscsiutil.h"

/*
 * NOTE: THIS IS A WORK IN PROGRESS. 
 *
 * For now, you must manually enter the host and target send and recv patterns 
 * (shown in the code below) beginning at line 104.  By default, this code will 
 * simulate the TCP traffic generated by an 8K iSCSI read between host and target.
 */

#define NUM_ITERS_DEFAULT         200
#define VERBOSE_FREQ_DEFAULT      20
#define PORT_DEFAULT              5001
#define HOST_SEND_PATTERN_DEFAULT "48"        /*  send iSCSI command PDU (SCSI READ) */
#define TARG_RECV_PATTERN_DEFAULT "48"
#define TARG_SEND_PATTERN_DEFAULT "48+8192"   /*  phase collapsed 8K data + status */
#define HOST_RECV_PATTERN_DEFAULT "48+8192" 

/*
 * Constants
 */

#define toSeconds(t) (t.tv_sec + (t.tv_usec/1000000.))
#define MAX_PATTERN_LEN 1024 
#define MAX_BUFFS MAX_PATTERN_LEN/2 


char usage[] = "usage: -t   <target IP>         I/O target\n"
               "       -hsp <host send pattern> e.g., 48\n"
               "       -tsp <targ recv pattern> e.g., 48\n"
               "       -hsp <targ repl pattern> e.g.. 8240\n"
               "       -hsp <host recv pattern> e.g., 48+8192\n"
               "       -n   <num iter>          number of iterations\n"
               "       -v   <freq>              verbose mode\n"
               "       -p   <port>              port number\n"
               "\nNOTE: The pattern args are not yet implemented.\n"
               "      You must manually edit usocktest.c to change\n"
               "      the request pattern which, by default, generates\n"
               "      TCP traffic identical to an 32 MB iSCSI read\n"
               "      that uses 8KB data PDUs.\n";

int main(int argc, char *argv[]) {
  int i, j, n;
  char HostSendPattern[MAX_PATTERN_LEN];
  char HostRecvPattern[MAX_PATTERN_LEN];
  char TargSendPattern[MAX_PATTERN_LEN];
  char TargRecvPattern[MAX_PATTERN_LEN];
  int HostSendSize[MAX_BUFFS];
  int HostRecvSize[MAX_BUFFS];
  int TargSendSize[MAX_BUFFS];
  int TargRecvSize[MAX_BUFFS];
  unsigned char* HostSendBuff[MAX_BUFFS];
  unsigned char* HostRecvBuff[MAX_BUFFS];
  unsigned char* TargSendBuff[MAX_BUFFS];
  unsigned char* TargRecvBuff[MAX_BUFFS];
  int NumHostSendBuffs;
  int NumHostRecvBuffs;
  int NumTargSendBuffs;
  int NumTargRecvBuffs;
  char ctrlBufferSend[MAX_PATTERN_LEN];
  char ctrlBufferRecv[MAX_PATTERN_LEN];
  unsigned ctrlBuffSize = MAX_PATTERN_LEN;
  struct timeval t_start, t_stop;
  double time;
  iscsi_socket_t iscsi_sock, iscsi_sock_new;
  int HostSendTotal, HostRecvTotal;
  int TargRecvTotal, TargSendTotal;
  int IsTarget;
  int Port = PORT_DEFAULT;
  int NumIters = NUM_ITERS_DEFAULT;
  int VerboseFreq = VERBOSE_FREQ_DEFAULT;
  char TargetIP[64] = "";

  /*
   * Parse command line
   */

  strcpy(HostSendPattern, HOST_SEND_PATTERN_DEFAULT);
  strcpy(HostRecvPattern, HOST_RECV_PATTERN_DEFAULT);
  strcpy(TargSendPattern, TARG_SEND_PATTERN_DEFAULT);
  strcpy(TargRecvPattern, TARG_RECV_PATTERN_DEFAULT);
  for (i=1; i<argc; i++) {
    if (!strcmp(argv[i], "-t")) {
      i++; strcpy(TargetIP, argv[i]);
    } else if (!strcmp(argv[i], "-p")) {
      i++; sscanf(argv[i], "%u", &Port);
    } else if (!strcmp(argv[i], "-n")) {
      i++; sscanf(argv[i], "%u", &NumIters);
    } else if (!strcmp(argv[i], "-v")) {
      i++; sscanf(argv[i], "%u", &VerboseFreq);
    } else {
      printf("Unknown option \"%s\"\n", argv[i]);
      printf("%s\n", usage);
      return -1;
    }
  }
  if (argc == 1) printf("%s\n", usage);
  IsTarget = (strlen(TargetIP)>0)?0:1;

  /* 
   * Convert command line string patterns here.  For now, you must 
   * manually enter these below.
   */

  NumHostSendBuffs = 1;
  HostSendSize[0]  = 48;
  NumTargRecvBuffs = 1;
  TargRecvSize[0]  = 48;
  NumHostRecvBuffs = 2;
  HostRecvSize[0]  = 48;
  HostRecvSize[1]  = 524288;
  NumTargSendBuffs = 2;
  TargSendSize[0]  = 48;
  TargSendSize[1]  = 524288;

  /* 
   * Create/bind/listen
   */

  if (iscsi_sock_create(&iscsi_sock)!=0) {
    iscsi_trace_error("iscsi_sock_create() failed\n");
    return -1;
  }
  if (IsTarget) {
    if (iscsi_sock_bind(iscsi_sock, Port)!=0) {
      iscsi_trace_error("iscsi_sock_bind() failed\n");
      return -1;
    }
    if (iscsi_sock_listen(iscsi_sock)!=0) {
      iscsi_trace_error("iscsi_sock_listen() failed\n");
      return -1;
    }
  }

  /* 
   * Accept connection
   */

accept:	
  if (IsTarget) {
    printf("Waiting for TCP connection on port %u\n", Port);
    if(iscsi_sock_accept(iscsi_sock, &iscsi_sock_new)!=0) {
      iscsi_trace_error("iscsi_sock_accept() failed\n");
      return -1;
    }
    printf("Connection accepted\n");
  } else {
    printf("Connecting to %s\n", TargetIP);
    if(iscsi_sock_connect(iscsi_sock, TargetIP, Port)!=0) {
      iscsi_trace_error("iscsi_sock_connect() failed\n");
      return -1;
    }
    printf("Connected\n");
    iscsi_sock_new = iscsi_sock;
  }

  /*
   * Host/Target handshake for test parameters
   */

  if (!IsTarget) {
    iscsi_trace(TRACE_DEBUG, "Sending test parameters\n");
    sprintf(ctrlBufferSend, "%s:%s:%s:%s:%i:%i:%i",
            HostSendPattern, HostRecvPattern, TargSendPattern, TargRecvPattern,
            NumIters, VerboseFreq, Port);
    if ((n=iscsi_sock_msg(iscsi_sock_new, 1, ctrlBuffSize, ctrlBufferSend, 0))!=ctrlBuffSize) {
      iscsi_trace_error("iscsi_sock_msg() failed\n");
      return -1;
    }
    if ((n=iscsi_sock_msg(iscsi_sock_new, 0, ctrlBuffSize, ctrlBufferRecv, 0))!=ctrlBuffSize) {
      iscsi_trace_error("iscsi_sock_msg() failed\n");
      return -1;
    }
    iscsi_trace(TRACE_DEBUG, "Test parameters sent\n");
  } else {
    char *ptr, *delim;

    iscsi_trace(TRACE_DEBUG, "Receiving test parameters\n");
    if ((n=iscsi_sock_msg(iscsi_sock_new, 0, ctrlBuffSize, ctrlBufferRecv, 0))!=ctrlBuffSize) {
      iscsi_trace_error("iscsi_sock_msg() failed\n");
      return -1;
    }
    ptr = ctrlBufferRecv; 
    delim = strchr(ptr, ':');
    strncpy(HostSendPattern, ptr, delim-ptr+1); HostSendPattern[delim-ptr] = 0x0; ptr = delim+1;
    delim = strchr(ptr, ':');
    strncpy(HostRecvPattern, ptr, delim-ptr+1); HostRecvPattern[delim-ptr] = 0x0; ptr = delim+1;
    delim = strchr(ptr, ':');
    strncpy(TargSendPattern, ptr, delim-ptr+1); TargSendPattern[delim-ptr] = 0x0; ptr = delim+1;
    delim = strchr(ptr, ':');
    strncpy(TargRecvPattern, ptr, delim-ptr+1); TargRecvPattern[delim-ptr] = 0x0; ptr = delim+1;
    sscanf(ptr, "%i:%i", &NumIters, &VerboseFreq);
    if ((n=iscsi_sock_msg(iscsi_sock_new, 1, ctrlBuffSize, ctrlBufferSend, 0))!=ctrlBuffSize) {
      iscsi_trace_error("iscsi_sock_msg() failed\n");
      return -1;
    }
    iscsi_trace(TRACE_DEBUG, "Test parameters received\n");
  }

  /* 
   * Check Arguments
   */
 
  HostSendTotal = 0; for (i=0; i<NumHostSendBuffs; i++) HostSendTotal += HostSendSize[i];
  TargRecvTotal = 0; for (i=0; i<NumTargRecvBuffs; i++) TargRecvTotal += TargRecvSize[i];
  if (HostSendTotal != TargRecvTotal) {
    iscsi_trace_error("Host sending size (%i) > Target receiving size (%i)\n", 
                HostSendTotal, TargRecvTotal); 
    return -1;
  }
  HostRecvTotal = 0; for (i=0; i<NumHostRecvBuffs; i++) HostRecvTotal += HostRecvSize[i];
  TargSendTotal = 0; for (i=0; i<NumTargSendBuffs; i++) TargSendTotal += TargSendSize[i];
  if (HostRecvTotal != TargSendTotal) {
    iscsi_trace_error("Host receiving size (%i) > Target sending size (%i)\n", 
                HostRecvTotal, TargSendTotal);
    return -1;
  }
  iscsi_trace(TRACE_DEBUG, "HostSendPattern: \"%s\"\n", HostSendPattern);
  iscsi_trace(TRACE_DEBUG, "HostRecvPattern: \"%s\"\n", HostRecvPattern);
  iscsi_trace(TRACE_DEBUG, "TargRecvPattern: \"%s\"\n", TargRecvPattern);
  iscsi_trace(TRACE_DEBUG, "TargSendPattern: \"%s\"\n", TargSendPattern);
  iscsi_trace(TRACE_DEBUG, "NumIters:        %i\n", NumIters);
  iscsi_trace(TRACE_DEBUG, "VerboseFreq:     %i\n", VerboseFreq);
  iscsi_trace(TRACE_DEBUG, "HostSendTotal:   %i bytes\n", HostSendTotal);
  iscsi_trace(TRACE_DEBUG, "HostRecvTotal:   %i bytes\n", HostRecvTotal);

  /*
   * Allocate buffers
   */

  for (i=0; i<NumHostSendBuffs; i++)
    if ((HostSendBuff[i]=iscsi_malloc(HostSendSize[i]))==NULL) {
      iscsi_trace_error("out of memory\n");
      return -1;
    }
  for (i=0; i<NumHostRecvBuffs; i++)
    if ((HostRecvBuff[i]=iscsi_malloc(HostRecvSize[i]))==NULL) {
      iscsi_trace_error("out of memory\n");
      return -1;
    }
  for (i=0; i<NumTargSendBuffs; i++)
    if ((TargSendBuff[i]=iscsi_malloc(TargSendSize[i]))==NULL) {
      iscsi_trace_error("out of memory\n");
      return -1;
    }
  for (i=0; i<NumTargRecvBuffs; i++)
    if ((TargRecvBuff[i]=iscsi_malloc(TargRecvSize[i]))==NULL) {
      iscsi_trace_error("out of memory\n");
      return -1;
    }


  /* 
   * Begin I/O
   */


  gettimeofday(&t_start, 0);
  for (i=0; i<NumIters; i++) {
    iscsi_trace(TRACE_DEBUG, "begin iteration %i\n", i);
    if (!IsTarget) {

      /*  Send to target */

      for (j=0; j<NumHostSendBuffs; j++) {
        if (iscsi_sock_msg(iscsi_sock_new, 1, HostSendSize[j], HostSendBuff[j], 0)!= HostSendSize[j]) {
          iscsi_trace_error("iscsi_sock_msg() failed\n");
          return -1;
        }
        iscsi_trace(TRACE_DEBUG, "Tx HostSendBuff[%i] (size %i)\n", j, HostSendSize[j]);
      }

      /*  Recv from target */

      for (j=0; j<NumHostRecvBuffs; j++) {
        if (iscsi_sock_msg(iscsi_sock_new, 0, HostRecvSize[j], HostRecvBuff[j], 0)!= HostRecvSize[j]) {
          iscsi_trace_error("iscsi_sock_msg() failed\n");
          return -1;
        }
        iscsi_trace(TRACE_DEBUG, "Rx HostRecvBuff[%i] (size %i)\n", j, HostRecvSize[j]);
      }
    } else {

      /*  Recv from host */

      for (j=0; j<NumTargRecvBuffs; j++) {
        if (iscsi_sock_msg(iscsi_sock_new, 0, TargRecvSize[j], TargRecvBuff[j], 0)!= TargRecvSize[j]) {
          iscsi_trace_error("iscsi_sock_msg() failed\n");
          return -1;
        }
        iscsi_trace(TRACE_DEBUG, "Rx TargRecvBuff[%i] (size %i)\n", j, TargRecvSize[j]);
      }

      /*  Send to host */

      for (j=0; j<NumTargSendBuffs; j++) {
        if (iscsi_sock_msg(iscsi_sock_new, 1, TargSendSize[j], TargSendBuff[j], 0)!= TargSendSize[j]) {
          iscsi_trace_error("iscsi_sock_msg() failed\n");
          return -1;
        }
        iscsi_trace(TRACE_DEBUG, "Tx TargSendBuff[%i] (size %i)\n", j, TargSendSize[j]);
      }
    }  
    if ((!IsTarget)&&((i+1)%VerboseFreq==0)) {
      printf("Iter %i: %i total bytes sent, %i total bytes recv\n", 
            i+1, HostSendTotal*(i+1), HostRecvTotal*(i+1));
    }
    iscsi_trace(TRACE_DEBUG, "end iteration %i\n", i);
  }
  gettimeofday(&t_stop, 0);

  /*
   * End I/O
   */


  /*  Free buffers */

  for (i=0; i<NumHostSendBuffs; i++) iscsi_free(HostSendBuff[i]);
  for (i=0; i<NumHostRecvBuffs; i++) iscsi_free(HostRecvBuff[i]);
  for (i=0; i<NumTargSendBuffs; i++) iscsi_free(TargSendBuff[i]);
  for (i=0; i<NumTargRecvBuffs; i++) iscsi_free(TargRecvBuff[i]);

  /*  Output stats  */

  if (IsTarget) {
    goto accept;
  } else {
    time = (double) (toSeconds(t_stop) - toSeconds(t_start));
    printf("Send Size:        %i bytes\n", HostSendTotal);
    printf("Recv Size:        %i bytes\n", HostRecvTotal);
    printf("Num Iters:        %i\n", NumIters);
    printf("Elapsed Time:     %.4f sec\n", time);
    printf("Avg RT Latency:   %.2f usec\n", (time*1000000/NumIters));
    printf("Send Performance: %.2f MB/sec sec\n", ((HostSendTotal*NumIters)/time)/1048576);
    printf("Recv Performance: %.2f MB/sec sec\n", ((HostRecvTotal*NumIters)/time)/1048576);
  } 
  return 0;
}