/* * 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; }