diff options
Diffstat (limited to 'src/netsh.c')
-rw-r--r-- | src/netsh.c | 1323 |
1 files changed, 1323 insertions, 0 deletions
diff --git a/src/netsh.c b/src/netsh.c new file mode 100644 index 0000000..1807e6b --- /dev/null +++ b/src/netsh.c @@ -0,0 +1,1323 @@ +#include "netperf_version.h" + +char netsh_id[]="\ +@(#)netsh.c (c) Copyright 1993-2012 Hewlett-Packard Company. Version 2.6.0"; + + +/****************************************************************/ +/* */ +/* Global include files */ +/* */ +/****************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifndef WIN32 +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#else +#include <time.h> +#include <winsock2.h> +#include "missing\stdint.h" +/* while it is unlikely that anyone running Windows 2000 or NT 4 is + going to be trying to compile this, if they are they will want to + define DONT_IPV6 in the sources file */ +#ifndef DONT_IPV6 +#include <ws2tcpip.h> +#endif +#define netperf_socklen_t socklen_t +extern int getopt(int , char **, char *) ; +#endif + + +#ifndef STRINGS +#include <string.h> +#else /* STRINGS */ +#include <strings.h> +#endif /* STRINGS */ + +/**********************************************************************/ +/* */ +/* Local Include Files */ +/* */ +/**********************************************************************/ + +#define NETSH +#include "netsh.h" +#include "netlib.h" +#include "nettest_bsd.h" + +#ifdef WANT_UNIX +#include "nettest_unix.h" +#endif /* WANT_UNIX */ + +#ifdef WANT_XTI +#include "nettest_xti.h" +#endif /* WANT_XTI */ + +#ifdef WANT_DLPI +#include "nettest_dlpi.h" +#endif /* WANT_DLPI */ + +#ifdef WANT_SCTP +#include "nettest_sctp.h" +#endif + +/************************************************************************/ +/* */ +/* Global constants and macros */ +/* */ +/************************************************************************/ + +/* Some of the args take optional parameters. Since we are using + getopt to parse the command line, we will tell getopt that they do + not take parms, and then look for them ourselves */ + +#define GLOBAL_CMD_LINE_ARGS "A:a:b:B:CcdD:f:F:H:hi:I:jk:K:l:L:n:NO:o:P:p:rSs:t:T:v:VW:w:y:Y:Z:46" + +/************************************************************************/ +/* */ +/* Global variables */ +/* */ +/************************************************************************/ + +/* some names and such */ +char *program; /* program invocation name */ +char *command_line; /* a copy of the entire command line */ + +/* stuff to say where this test is going */ +char + host_name[HOSTNAMESIZE] = "", /* remote host name or ip addr */ + local_host_name[HOSTNAMESIZE] = "", /* local hostname or ip */ + test_name[BUFSIZ] = "TCP_STREAM", /* which test to run */ + test_port[PORTBUFSIZE] = "12865", /* where is the test waiting */ + local_test_port[PORTBUFSIZE] = "0"; /* from whence we should start */ + +int + address_family = AF_UNSPEC, /* which address family remote */ + local_address_family = AF_UNSPEC; /* which address family local */ + +/* the source of data for filling the buffers */ +char local_fill_file[BUFSIZ] = ""; +char remote_fill_file[32] = ""; /* size limited for control message */ + +/* output controlling variables */ +int + debug = 0, /* debugging level */ + print_headers = 1, /* do/don't display headers */ + verbosity = 1, /* verbosity level */ + keep_histogram = 0, + keep_statistics = 0; + +/* When specified with -B, this will be displayed at the end of the line + for output that does not include the test header. mostly this is + to help identify a specific netperf result when concurrent netperfs + are run. raj 2006-02-01 */ +char *result_brand = NULL; + +/* cpu variables */ +int + local_cpu_usage = 0, /* you guessed it */ + remote_cpu_usage = 0; /* still right ! */ + +float + local_cpu_rate = 0.0F, + remote_cpu_rate = 0.0F; + +int + shell_num_cpus=1; + +/* the end-test conditions for the tests - either transactions, bytes, + or time. different vars used for clarity - space is cheap ;-) */ + +int + test_time = 10, /* test ends by time */ + test_len_ticks, /* how many times will the timer go off before the + test is over? */ + test_bytes = 0, /* test ends on byte count */ + test_trans = 0; /* test ends on tran count */ + +/* the alignment conditions for the tests */ +int + local_recv_align = 8, /* alignment for local receives */ + local_send_align = 8, /* alignment for local sends */ + local_send_offset = 0, + local_recv_offset = 0, + remote_recv_align = 8, /* alignment for remote receives */ + remote_send_align = 8, /* alignment for remote sends */ + remote_send_offset = 0, + remote_recv_offset = 0, + remote_send_width = 0, + remote_recv_width = 0; + +/* hoist above the if for omni */ +int + interval_usecs = 0, + interval_wate = 0, + interval_burst = 0, + remote_interval_usecs = 0, + remote_interval_burst = 0; + +/* wait time between control/data connection establishment and start + of data traffic */ +int wait_time_secs = 0; + + +#ifdef DIRTY +int loc_dirty_count = 0, + loc_clean_count = 0, + rem_dirty_count = 0, + rem_clean_count = 0; +#else +int loc_dirty_count = -1, + loc_clean_count = -1, + rem_dirty_count = -1, + rem_clean_count = -1; +#endif /* DIRTY */ + + /* some of the vairables for confidence intervals... */ + +int confidence_level = 0; +int iteration_min = 1; +int iteration_max = 1; +int result_confidence_only = 0; +double interval = 0.0; + + /* stuff to control the "width" of the buffer rings for sending and + receiving data */ +int send_width; +int recv_width; + +/* address family */ +int af = AF_INET; + +/* socket priority via SO_PRIORITY */ +int local_socket_prio = -1; +int remote_socket_prio = -1; + +/* and IP_TOS */ +int local_socket_tos = -1; +int remote_socket_tos = -1; + +/* did someone request processor affinity? */ +int cpu_binding_requested = 0; + +/* are we not establishing a control connection? */ +int no_control = 0; + +/* what is the passphrase? */ +char *passphrase = NULL; + +char netserver_usage[] = "\n\ +Usage: netserver [options] \n\ +\n\ +Options:\n\ + -h Display this text\n\ + -D Do not daemonize\n\ + -d Increase debugging output\n\ + -f Do not spawn chilren for each test, run serially\n\ + -L name,family Use name to pick listen address and family for family\n\ + -N No debugging output, even if netperf asks\n\ + -p portnum Listen for connect requests on portnum.\n\ + -4 Do IPv4\n\ + -6 Do IPv6\n\ + -v verbosity Specify the verbosity level\n\ + -V Display version information and exit\n\ + -Z passphrase Expect passphrase as the first thing received\n\ +\n"; + +/* netperf_usage done as two concatenated strings to make the MS + compiler happy when compiling for x86_32. fix from Spencer + Frink. */ + +char netperf_usage1[] = "\n\ +Usage: netperf [global options] -- [test options] \n\ +\n\ +Global options:\n\ + -a send,recv Set the local send,recv buffer alignment\n\ + -A send,recv Set the remote send,recv buffer alignment\n\ + -B brandstr Specify a string to be emitted with brief output\n\ + -c [cpu_rate] Report local CPU usage\n\ + -C [cpu_rate] Report remote CPU usage\n\ + -d Increase debugging output\n\ + -D time,[units] * Display interim results at least every time interval\n\ + using units as the initial guess for units per second\n\ + A negative value for time will make heavy use of the\n\ + system's timestamping functionality\n\ + -f G|M|K|g|m|k Set the output units\n\ + -F lfill[,rfill]* Pre-fill buffers with data from specified file\n\ + -h Display this text\n\ + -H name|ip,fam * Specify the target machine and/or local ip and family\n\ + -i max,min Specify the max and min number of iterations (15,1)\n\ + -I lvl[,intvl] Specify confidence level (95 or 99) (99) \n\ + and confidence interval in percentage (10)\n\ + -j Keep additional timing statistics\n\ + -l testlen Specify test duration (>0 secs) (<0 bytes|trans)\n\ + -L name|ip,fam * Specify the local ip|name and address family\n\ + -o send,recv Set the local send,recv buffer offsets\n\ + -O send,recv Set the remote send,recv buffer offset\n\ + -n numcpu Set the number of processors for CPU util\n\ + -N Establish no control connection, do 'send' side only\n\ + -p port,lport* Specify netserver port number and/or local port\n\ + -P 0|1 Don't/Do display test headers\n\ + -r Allow confidence to be hit on result only\n\ + -s seconds Wait seconds between test setup and test start\n\ + -S Set SO_KEEPALIVE on the data connection\n\ + -t testname Specify test to perform\n\ + -T lcpu,rcpu Request netperf/netserver be bound to local/remote cpu\n\ + -v verbosity Specify the verbosity level\n\ + -W send,recv Set the number of send,recv buffers\n\ + -v level Set the verbosity level (default 1, min 0)\n\ + -V Display the netperf version and exit\n\ + -y local,remote Set the socket priority\n\ + -Y local,remote Set the IP_TOS. Use hexadecimal.\n\ + -Z passphrase Set and pass to netserver a passphrase\n"; + +char netperf_usage2[] = "\n\ +For those options taking two parms, at least one must be specified;\n\ +specifying one value without a comma will set both parms to that\n\ +value, specifying a value with a leading comma will set just the second\n\ +parm, a value with a trailing comma will set just the first. To set\n\ +each parm to unique values, specify both and separate them with a\n\ +comma.\n\ +\n" +"* For these options taking two parms, specifying one value with no comma\n\ +will only set the first parms and will leave the second at the default\n\ +value. To set the second value it must be preceded with a comma or be a\n\ +comma-separated pair. This is to retain previous netperf behaviour.\n"; + + +/* This routine will return the two arguments to the calling routine. + If the second argument is not specified, and there is no comma, + then the value of the second argument will be the same as the value + of the first. If there is a comma, then the value of the second + argument will be the value of the second argument ;-) */ +void +break_args(char *s, char *arg1, char *arg2) + +{ + char *ns; + ns = strchr(s,','); + if (ns) { + /* there was a comma arg2 should be the second arg*/ + *ns++ = '\0'; + while ((*arg2++ = *ns++) != '\0'); + } + else { + /* there was not a comma, we can use ns as a temp s */ + /* and arg2 should be the same value as arg1 */ + ns = s; + while ((*arg2++ = *ns++) != '\0'); + }; + while ((*arg1++ = *s++) != '\0'); +} + +/* break_args_explicit_sep + + this routine is somewhat like break_args in that it will separate a + pair of values using the given separator. however, if there is no + separator this version will not ass-u-me that arg2 should be the + same as arg1. raj 20101129 */ + +void +break_args_explicit_sep(char *s, int sep, char *arg1, char *arg2) + +{ + char *ns; + ns = strchr(s,sep); + if (ns) { + /* there was a separator arg2 should be the second arg*/ + *ns++ = '\0'; + while ((*arg2++ = *ns++) != '\0'); + } + else { + /* there was no separator, so we should make sure that arg2 is \0 + lest something become confused. raj 2005-02-04 */ + *arg2 = '\0'; + }; + while ((*arg1++ = *s++) != '\0'); + +} + +/* break_args_explicit - now just a wrapper around a call to + break_args_explicit_sep passing-in a ',' as the separator. raj + 20101129 */ + +void +break_args_explicit(char *s, char *arg1, char *arg2) + +{ + break_args_explicit_sep(s, ',', arg1, arg2); +} + + +/* given a string with possible values for setting an address family, + convert that into one of the AF_mumble values - AF_INET, AF_INET6, + AF_UNSPEC as apropriate. the family_string is compared in a + case-insensitive manner */ + +int +parse_address_family(char family_string[]) +{ + + char temp[10]; /* gotta love magic constants :) */ + + strncpy(temp,family_string,10); + + if (debug) { + fprintf(where, + "Attempting to parse address family from %s derived from %s\n", + temp, + family_string); + } +#if defined(AF_INET6) + if (strstr(temp,"6")) { + return(AF_INET6); + } +#endif + if (strstr(temp,"inet") || + strstr(temp,"4")) { + return(AF_INET); + } +#if defined(AF_RDS) + if (strstr(temp,"af_rds") || + strstr(temp,"32")) { + return(AF_RDS); + } +#endif + if (strstr(temp,"unspec") || + strstr(temp,"0")) { + return(AF_UNSPEC); + } + fprintf(where, + "WARNING! %s not recognized as an address family, using AF_UNPSEC\n" + "Are you sure netperf was configured for that address family?\n", + family_string); + fflush(where); + return(AF_UNSPEC); +} + +int +parse_socket_type(char socket_string[]) { + + char temp[10]; + + strncpy(temp,socket_string,10); + + if (debug) { + fprintf(where, + "Attempting to parse socket type from %s derived from %s\n", + temp, + socket_string); + } + +#ifdef SOCK_STREAM + if (strstr(temp,"stream")) + return SOCK_STREAM; +#endif +#ifdef SOCK_DGRAM + if (strstr(temp,"dgram")) + return SOCK_DGRAM; +#endif + return NST_UNKN; + +} + +int +parse_direction(char direction_string[]) +{ + char arg1[BUFSIZ],arg2[BUFSIZ]; + int left, right; + + if (NULL == direction_string) { + return 0; + } + + if (direction_string[0] == '\0') { + return 0; + } + + /* allow someone to "or" break_args_explicit will split at the first + '|' in the string so we know that arg1 has no '|' in it and arg2 + might */ + break_args_explicit_sep(direction_string,'|',arg1,arg2); + + /* at this point only arg2 could contain a '|' so recurse on that */ + right = parse_direction(arg2); + + /* now we parse the "left side" or arg1 */ + if (arg1[0] == '\0') { + left = 0; + } + else if ((strcasecmp(arg1,"xmit") == 0) || + (strcasecmp(arg1,"send") == 0) || + (strcasecmp(arg1,"stream") == 0) || + (strcasecmp(arg1,"transmit") == 0)) { + left = NETPERF_XMIT; + } + else if ((strcasecmp(arg1,"recv") == 0) || + (strcasecmp(arg1,"receive") == 0) || + (strcasecmp(arg1,"maerts") == 0)) { + /* yes, another magic number... */ + left = NETPERF_RECV; + } + else if (strcasecmp(arg1,"rr") == 0) { + left = NETPERF_XMIT|NETPERF_RECV; + } + else { + /* we now "ass-u-me" it is a number that can be parsed by strtol() + */ + left = strtol(arg1,NULL,0); + } + + return (left | right); + +} + +int +parse_protocol(char protocol_string[]) +{ + char temp[10]; + + strncpy(temp,protocol_string,10); + + if (debug) { + fprintf(where, + "Attempting to parse protocol from %s derived from %s\n", + temp, + protocol_string); + } + + /* we ass-u-me that everyone has IPPROTO_TCP elsewhere so might as + well here, and avoid issues with windows using an enum. Kudos to + Jonathan Cook. */ + if (!strcasecmp(temp,"tcp")){ + socket_type = SOCK_STREAM; + return IPPROTO_TCP; + } + + if (!strcasecmp(temp,"udp")) { + socket_type = SOCK_DGRAM; + return IPPROTO_UDP; + } + + /* we keep the rest of the #idefs though because these may not be as + universal as TCP and UDP... */ +#ifdef IPPROTO_SCTP + if (!strcasecmp(temp,"sctp")) { + /* it can be more than one socket type */ + return IPPROTO_SCTP; + } +#endif +#ifdef IPPROTO_SDP + if (!strcasecmp(temp,"sdp")) { + socket_type = SOCK_STREAM; + return IPPROTO_SDP; + } +#endif +#if defined(IPPROTO_DCCP) && defined(SOCK_DCCP) + if (!strcasecmp(temp,"dccp")) { + socket_type = SOCK_DCCP; + return IPPROTO_DCCP; + } +#endif +#ifdef IPPROTO_UDPLITE + if (!strcasecmp(temp,"udplite")) { + socket_type = SOCK_DGRAM; + return IPPROTO_UDPLITE; + } +#endif + return IPPROTO_IP; +} + + +void +print_netserver_usage() +{ + fprintf(stderr, "%s", netserver_usage); +} + + +void +print_netperf_usage() +{ + fprintf(stderr, "%s%s", netperf_usage1, netperf_usage2); +} + +/* convert the specified string to upper case if we know how */ +static void +convert_to_upper(char *source) +{ +#if defined(HAVE_TOUPPER) + int i,length; + + length = strlen(source); + + for (i=0; i < length; i++) { + source[i] = toupper(source[i]); + } +#endif + return; + +} + +void +scan_cmd_line(int argc, char *argv[]) +{ + extern int optind; /* index of first unused arg */ + extern char *optarg; /* pointer to option string */ + + int cmnd_len; + char *p; + + int c; + + char arg1[BUFSIZ], /* argument holders */ + arg2[BUFSIZ]; + + program = (char *)malloc(strlen(argv[0]) + 1); + if (program == NULL) { + printf("malloc() to store program name failed!\n"); + exit(-1); + } + strcpy(program, argv[0]); + + /* brute force, but effective */ + command_line = NULL; + cmnd_len = 0; + for (c = 0; c < argc; c++) { + cmnd_len += strlen(argv[c]); + } + cmnd_len += argc; /* forget thee not the spaces */ + command_line = malloc(cmnd_len+1); + + if (command_line == NULL) { + printf("malloc(%d) failed!\n",cmnd_len); + exit(-1); + } + p = command_line; + for (c = 0; c < argc; c++) { + memcpy(p,argv[c],strlen(argv[c])); + p += strlen(argv[c]); + *p = ' '; + p += 1; + } + *--p = 0; + + /* Go through all the command line arguments and break them out. For + those options that take two parms, specifying only the first will + set both to that value. Specifying only the second will leave the + first untouched. To change only the first, use the form first, + (see the routine break_args.. */ + + while ((c= getopt(argc, argv, GLOBAL_CMD_LINE_ARGS)) != EOF) { + switch (c) { + case '?': + case 'h': + print_netperf_usage(); + exit(1); + case 'a': + /* set local alignments */ + break_args(optarg,arg1,arg2); + if (arg1[0]) { + local_send_align = convert(arg1); + } + if (arg2[0]) + local_recv_align = convert(arg2); + break; + case 'A': + /* set remote alignments */ + break_args(optarg,arg1,arg2); + if (arg1[0]) { + remote_send_align = convert(arg1); + } + if (arg2[0]) + remote_recv_align = convert(arg2); + break; + case 'c': + /* measure local cpu usage please. the user may have specified + the cpu rate as an optional parm */ + if (argv[optind] && isdigit((unsigned char)argv[optind][0])){ + /* there was an optional parm */ + local_cpu_rate = (float)atof(argv[optind]); + optind++; + } + local_cpu_usage++; + break; + case 'C': + /* measure remote cpu usage please */ + if (argv[optind] && isdigit((unsigned char)argv[optind][0])){ + /* there was an optional parm */ + remote_cpu_rate = (float)atof(argv[optind]); + optind++; + } + remote_cpu_usage++; + break; + case 'd': + debug++; + break; + case 'D': +#if (defined WANT_DEMO) + demo_mode = 1; /* 1 == use units; 2 == always timestamp */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) { + demo_interval = atof(arg1) * 1000000.0; + if (demo_interval < 0.0) { + demo_interval = demo_interval * -1.0; + demo_mode = 2; + } + } + if (arg2[0]) { + demo_units = convert(arg2); + } +#else + printf("Sorry, Demo Mode not configured into this netperf.\n" + "Please consider reconfiguring netperf with\n" + "--enable-demo=yes and recompiling\n"); +#endif + break; + case 'f': + /* set the thruput formatting */ + libfmt = *optarg; + break; + case 'F': + /* set the fill_file variables for pre-filling buffers. check + the remote fill file name length against our limit as we will + not hear from the remote on errors opening the fill + file. Props to Jonathan Cook for the remote name check */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) { + strncpy(local_fill_file,arg1,sizeof(local_fill_file)); + local_fill_file[sizeof(local_fill_file) - 1] = '\0'; + } + if (arg2[0]) { + if (strlen(arg2)>(sizeof(remote_fill_file) - 1)){ + fprintf(stderr, + "Remote fill file name must be less than %d characters\n", + (int) sizeof(remote_fill_file)); + fflush(stderr); + exit(-1); + } + + strncpy(remote_fill_file,arg2,sizeof(remote_fill_file)); + remote_fill_file[sizeof(remote_fill_file) - 1] = '\0'; + } + break; + case 'i': + /* set the iterations min and max for confidence intervals */ + break_args(optarg,arg1,arg2); + if (arg1[0]) { + iteration_max = convert(arg1); + } + if (arg2[0] ) { + iteration_min = convert(arg2); + } + /* if the iteration_max is < iteration_min make iteration_max + equal iteration_min */ + if (iteration_max < iteration_min) iteration_max = iteration_min; + /* limit minimum to 3 iterations */ + if (iteration_max < 3) iteration_max = 3; + if (iteration_min < 3) iteration_min = 3; + /* limit maximum to 30 iterations */ + if (iteration_max > 30) iteration_max = 30; + if (iteration_min > 30) iteration_min = 30; + if (confidence_level == 0) confidence_level = 99; + if (interval == 0.0) interval = 0.05; /* five percent */ + break; + case 'I': + /* set the confidence level (95 or 99) and width */ + break_args(optarg,arg1,arg2); + if (arg1[0]) { + confidence_level = convert(arg1); + } + if((confidence_level != 95) && (confidence_level != 99)){ + printf("Only 95%% and 99%% confidence level is supported\n"); + exit(-1); + } + if (arg2[0] ) { + /* it doesn't make much sense to use convert() here so just + use strtod() instead. raj 2007-10-24 */ + interval = strtod(arg2,NULL)/100.0; + } + /* make sure that iteration_min and iteration_max are at least + at a reasonable default value. if a -i option has previously + been parsed, these will no longer be 1, so we can check + against 1 */ + if (iteration_min == 1) iteration_min = 3; + if (iteration_max == 1) iteration_max = 10; + /* make sure that the interval is set if it isn't at its default + value */ + if (interval == 0.0) interval = 0.05; /* five percent */ + break; + case 'j': + keep_histogram = 1; + keep_statistics = 1; + break; + case 'k': + /* local dirty and clean counts */ +#ifdef DIRTY + break_args(optarg,arg1,arg2); + if (arg1[0]) { + loc_dirty_count = convert(arg1); + } + if (arg2[0] ) { + loc_clean_count = convert(arg2); + } +#else + printf("I don't know how to get dirty.\n"); +#endif /* DIRTY */ + break; + case 'K': + /* remote dirty and clean counts */ +#ifdef DIRTY + break_args(optarg,arg1,arg2); + if (arg1[0]) { + rem_dirty_count = convert(arg1); + } + if (arg2[0] ) { + rem_clean_count = convert(arg2); + } +#else + printf("I don't know how to get dirty.\n"); +#endif /* DIRTY */ + break; + case 'n': + shell_num_cpus = atoi(optarg); + break; + case 'N': + no_control = 1; + break; + case 'o': + /* set the local offsets */ + break_args(optarg,arg1,arg2); + if (arg1[0]) + local_send_offset = convert(arg1); + if (arg2[0]) + local_recv_offset = convert(arg2); + break; + case 'O': + /* set the remote offsets */ + break_args(optarg,arg1,arg2); + if (arg1[0]) + remote_send_offset = convert(arg1); + if (arg2[0]) + remote_recv_offset = convert(arg2); + break; + case 'P': + /* to print or not to print, that is */ + /* the header question */ + print_headers = convert(optarg); + break; + case 'r': + /* the user wishes that we declare confidence when hit on the + result even if not yet reached on CPU utilization. only + meaningful if cpu util is enabled */ + result_confidence_only = 1; + break; + case 'S': + /* the user wishes us to set SO_KEEPALIVE */ + want_keepalive = 1; + break; + case 's': + /* the user wishes us to sleep/pause some length of time before + actually starting the test */ + wait_time_secs = convert(optarg); + break; + case 't': + /* set the test name and shift it to upper case so we don't have + to worry about compares on things like substrings */ + strncpy(test_name,optarg,sizeof(test_name)-1); + convert_to_upper(test_name); + break; + case 'T': + /* We want to set the processor on which netserver or netperf + will run */ + break_args(optarg,arg1,arg2); + if (arg1[0]) { + local_proc_affinity = convert(arg1); + bind_to_specific_processor(local_proc_affinity,0); + } + if (arg2[0]) { + remote_proc_affinity = convert(arg2); + } + cpu_binding_requested = 1; + break; + case 'W': + /* set the "width" of the user space data buffer ring. This will + be the number of send_size buffers malloc'd in the tests */ + break_args(optarg,arg1,arg2); + if (arg1[0]) + send_width = convert(arg1); + if (arg2[0]) + recv_width = convert(arg2); + break; + case 'y': + break_args(optarg, arg1, arg2); +#if defined(SO_PRIORITY) + if (arg1[0]) + local_socket_prio = convert(arg1); +#else + if (debug) { + fprintf(where, + "Setting SO_PRIORITY is not supported on this platform, request to set SO_PRIORITY locally ignored.\n"); + fflush(where); + } + local_socket_prio = -3; +#endif + if (arg2[0]) + remote_socket_prio = convert(arg2); + break; + case 'Y': + break_args(optarg, arg1, arg2); +#if defined(IP_TOS) || defined(IPV6_TCLASS) + if (arg1[0]) + local_socket_tos = parse_ipqos(arg1); +#else + if (debug) { + fprintf(where, + "Setting IP type-of-service is not supported on this platform, request to set it locally ignored.\n"); + fflush(where); + } + local_socket_tos = -1; +#endif + if (arg2[0]) { + remote_socket_tos = parse_ipqos(arg2); + if (debug) { + fprintf(where, + "Setting remote_socket_tos to 0x%x\n", + remote_socket_tos); + fflush(where); + } + } + break; + case 'Z': + /* only copy as much of the passphrase as could fit in the + test-specific portion of a control message. Windows does not + seem to have a strndup() so just malloc and strncpy it. we + weren't checking the strndup() return so won't bother with + checking malloc(). we will though make certain we only + allocated it once in the event that someone puts -Z on the + command line more than once */ + if (passphrase == NULL) + passphrase = malloc(sizeof(netperf_request.content.test_specific_data)); + strncpy(passphrase, + optarg, + sizeof(netperf_request.content.test_specific_data)); + passphrase[sizeof(netperf_request.content.test_specific_data) - 1] = '\0'; + break; + case 'l': + /* determine test end conditions */ + /* assume a timed test */ + test_time = convert(optarg); + test_bytes = test_trans = 0; + if (test_time < 0) { + test_bytes = -1 * test_time; + test_trans = test_bytes; + test_time = 0; + } + break; + case 'v': + /* say how much to say */ + verbosity = convert(optarg); + break; + case 'p': + /* specify an alternate port number we use break_args_explicit + here to maintain backwards compatibility with previous + generations of netperf where having a single value did not + set both remote _and_ local port number. raj 2005-02-04 */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) + strncpy(test_port,arg1,PORTBUFSIZE); + if (arg2[0]) + strncpy(local_test_port,arg2,PORTBUFSIZE); + break; + case 'H': + /* save-off the host identifying information, use + break_args_explicit since passing just one value should not + set both */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) + strncpy(host_name,arg1,sizeof(host_name)); + if (arg2[0]) + address_family = parse_address_family(arg2); + break; + case 'L': + /* save-off the local control socket addressing information. use + break_args_explicit since passing just one value should not + set both */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) + strncpy(local_host_name,arg1,sizeof(local_host_name)); + if (arg2[0]) + local_address_family = parse_address_family(arg2); + break; + case 'w': + /* We want to send requests at a certain wate. Remember that + there are 1000000 usecs in a second, and that the packet rate + is expressed in packets per millisecond. shuffle the #ifdef + around a bit to deal with both netperf and netserver possibly + doing intervals with omni tests */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) { +#ifdef WANT_INTERVALS + interval_usecs = convert_timespec(arg1); + interval_wate = interval_usecs / 1000; +#else + fprintf(where, + "Packet rate control is not compiled in.\n"); +#endif + } + if (arg2[0]) { + /* we pass usecs to the remote and let it deal to cover both + intervals and spin methods. if he wasn't intervals enabled + he will return a suitable value back to us */ + remote_interval_usecs = convert_timespec(arg2); + } + break; + case 'b': + /* we want to have a burst so many packets per */ + /* interval. */ + break_args_explicit(optarg,arg1,arg2); + if (arg1[0]) { +#ifdef WANT_INTERVALS + interval_burst = convert(arg1); + /* set a default in case the user does not include the -w + option */ + if (interval_usecs == 0) { + interval_wate = 1; + interval_usecs = 1000; + } +#else + fprintf(where, + "Packet burst size is not compiled in. \n"); +#endif /* WANT_INTERVALS */ + } + /* there is no ifdef here because we are sending this value to + the remote, which may or may not have been compiled for + intervals and we don't have a way of knowing on this side + until we try */ + if (arg2[0]) { + remote_interval_burst = convert(arg2); + if (remote_interval_usecs == 0) { + remote_interval_usecs = 1000; + } + } + break; + case 'B': + result_brand = malloc(strlen(optarg)+1); + if (NULL != result_brand) { + strcpy(result_brand,optarg); + } + else { + fprintf(where, + "Unable to malloc space for result brand\n"); + } + break; + case '4': + address_family = AF_INET; + local_address_family = AF_INET; + break; + case '6': +#if defined(AF_INET6) + address_family = AF_INET6; + local_address_family = AF_INET6; +#else + printf("This netperf was not compiled on an IPv6 capable system!\n"); + exit(-1); +#endif + break; + case 'V': + printf("Netperf version %s\n",NETPERF_VERSION); + exit(0); + break; + }; + } + /* ok, what should our default hostname and local binding info be? + */ + + if ('\0' == host_name[0]) { + /* host_name was not set */ + switch (address_family) { + case AF_INET: +#if defined(AF_RDS) + case AF_RDS: +#endif + strcpy(host_name,"localhost"); + break; + case AF_UNSPEC: + /* what to do here? case it off the local_address_family I + suppose */ + switch (local_address_family) { + case AF_INET: + case AF_UNSPEC: +#if defined(AF_RDS) + case AF_RDS: +#endif + strcpy(host_name,"localhost"); + break; +#if defined(AF_INET6) + case AF_INET6: + strcpy(host_name,"::1"); + break; +#endif + default: + printf("Netperf does not understand %d as an address family\n", + address_family); + exit(-1); + } + break; +#if defined(AF_INET6) + case AF_INET6: + strcpy(host_name,"::1"); + break; +#endif + default: + printf("Netperf does not understand %d as an address family\n", + address_family); + exit(-1); + } + } else { + /* resolve the hostname and pull the address family from the + addrinfo */ + struct addrinfo *ai; + + ai = resolve_host(host_name, NULL, address_family); + if (!ai) { + printf("Netperf could not resolve %s as a host name\n", host_name); + exit(-1); + } + address_family = ai->ai_family; + freeaddrinfo(ai); + } + + + /* now, having established the name to which the control will + connect, from what should it come? */ + if ('\0' == local_host_name[0]) { + switch (local_address_family) { + case AF_INET: +#if defined(AF_RDS) + case AF_RDS: +#endif + strcpy(local_host_name,"0.0.0.0"); + break; + case AF_UNSPEC: + switch (address_family) { + case AF_INET: + case AF_UNSPEC: +#if defined(AF_RDS) + case AF_RDS: +#endif + strcpy(local_host_name,"0.0.0.0"); + break; +#if defined(AF_INET6) + case AF_INET6: + strcpy(local_host_name,"::0"); + break; +#endif + default: + printf("Netperf does not understand %d as an address family\n", + address_family); + exit(-1); + } + break; +#if defined(AF_INET6) + case AF_INET6: + strcpy(local_host_name,"::0"); + break; +#endif + default: + printf("Netperf does not understand %d as an address family\n", + address_family); + exit(-1); + } + } + + /* so, if we aren't even going to establish a control connection we + should set certain "remote" settings to reflect this, regardless + of what else may have been set on the command line */ + if (no_control) { + remote_socket_prio = -1; + remote_socket_tos = -1; + remote_recv_align = -1; + remote_send_align = -1; + remote_send_offset = -1; + remote_recv_offset = -1; + remote_cpu_rate = (float)-1.0; + remote_cpu_usage = 0; + } + + /* parsing test-specific options used to be conditional on there + being a "--" in the option stream. however, some of the tests + have other initialization happening in their "scan" routines so + we want to call them regardless. raj 2005-02-08 */ + /* while the parsing of the command line will upshift the test name, + since we don't know that there will always be a way to do so? we + will retain for now the strcasecmp calls rather than switch to + strcmp. raj 20101220 */ + if ( +#ifndef WANT_MIGRATION + (strcasecmp(test_name,"TCP_STREAM") == 0) || + (strcasecmp(test_name,"TCP_MAERTS") == 0) || + (strcasecmp(test_name,"TCP_RR") == 0) || + (strcasecmp(test_name,"TCP_CRR") == 0) || + (strcasecmp(test_name,"UDP_STREAM") == 0) || + (strcasecmp(test_name,"UDP_RR") == 0) || +#endif +#ifdef HAVE_ICSC_EXS + (strcasecmp(test_name,"EXS_TCP_STREAM") == 0) || +#endif /* HAVE_ICSC_EXS */ +#ifdef HAVE_SENDFILE + (strcasecmp(test_name,"TCP_SENDFILE") == 0) || +#endif /* HAVE_SENDFILE */ + (strcasecmp(test_name,"TCP_CC") == 0) || + (strcasecmp(test_name,"TCP_MSS") == 0) || +#ifdef DO_1644 + (strcasecmp(test_name,"TCP_TRR") == 0) || +#endif /* DO_1644 */ +#ifdef DO_NBRR + (strcasecmp(test_name,"TCP_TRR") == 0) || +#endif /* DO_NBRR */ + (0)) + { + scan_sockets_args(argc, argv); + } + +#ifdef WANT_DLPI + else if ((strcasecmp(test_name,"DLCO_RR") == 0) || + (strcasecmp(test_name,"DLCL_RR") == 0) || + (strcasecmp(test_name,"DLCO_STREAM") == 0) || + (strcasecmp(test_name,"DLCL_STREAM") == 0)) + { + scan_dlpi_args(argc, argv); + } +#endif /* WANT_DLPI */ + +#ifdef WANT_UNIX + else if ((strcasecmp(test_name,"STREAM_RR") == 0) || + (strcasecmp(test_name,"DG_RR") == 0) || + (strcasecmp(test_name,"STREAM_STREAM") == 0) || + (strcasecmp(test_name,"DG_STREAM") == 0)) + { + scan_unix_args(argc, argv); + } +#endif /* WANT_UNIX */ + +#ifdef WANT_XTI + else if ((strcasecmp(test_name,"XTI_TCP_RR") == 0) || + (strcasecmp(test_name,"XTI_TCP_STREAM") == 0) || + (strcasecmp(test_name,"XTI_UDP_RR") == 0) || + (strcasecmp(test_name,"XTI_UDP_STREAM") == 0)) + { + scan_xti_args(argc, argv); + } +#endif /* WANT_XTI */ + +#ifdef WANT_SCTP + else if ((strcasecmp(test_name,"SCTP_STREAM") == 0) || + (strcasecmp(test_name,"SCTP_RR") == 0) || + (strcasecmp(test_name,"SCTP_STREAM_MANY") == 0) || + (strcasecmp(test_name,"SCTP_RR_MANY") == 0)) + { + scan_sctp_args(argc, argv); + } +#endif + +#ifdef WANT_SDP + else if((strcasecmp(test_name,"SDP_STREAM") == 0) || + (strcasecmp(test_name,"SDP_MAERTS") == 0) || + (strcasecmp(test_name,"SDP_RR") == 0)) + { + scan_sdp_args(argc, argv); + } +#endif + +#ifdef WANT_OMNI + else if ((strcasecmp(test_name,"OMNI") == 0) || +#ifdef WANT_MIGRATION + (strcasecmp(test_name,"TCP_STREAM") == 0) || + (strcasecmp(test_name,"TCP_MAERTS") == 0) || + (strcasecmp(test_name,"TCP_RR") == 0) || + (strcasecmp(test_name,"TCP_CRR") == 0) || + (strcasecmp(test_name,"UDP_STREAM") == 0) || + (strcasecmp(test_name,"UDP_RR") == 0) || +#endif + (strcasecmp(test_name,"UUID") == 0)) { + scan_omni_args(argc, argv); + } +#endif + + /* what is our default value for the output units? if the test + name contains "RR" or "rr" or "Rr" or "rR" then the default is + 'x' for transactions. otherwise it is 'm' for megabits (10^6) + however... if this is an "omni" test then we want to defer + this decision to scan_omni_args */ + + if (strcasecmp(test_name,"omni")) { + if ('?' == libfmt) { + /* we use a series of strstr's here because not everyone has + strcasestr and I don't feel like up or downshifting text */ + if ((strstr(test_name,"RR")) || + (strstr(test_name,"rr")) || + (strstr(test_name,"Rr")) || + (strstr(test_name,"rR"))) { + libfmt = 'x'; + } + else { + libfmt = 'm'; + } + } + else if ('x' == libfmt) { + /* now, a format of 'x' makes no sense for anything other than + an RR test. if someone has been silly enough to try to set + that, we will reset it silently to default - namely 'm' */ + if ((strstr(test_name,"RR") == NULL) && + (strstr(test_name,"rr") == NULL) && + (strstr(test_name,"Rr") == NULL) && + (strstr(test_name,"rR") == NULL)) { + libfmt = 'm'; + } + } + } +} + + +void +dump_globals() +{ + printf("Program name: %s\n", program); + printf("Local send alignment: %d\n",local_send_align); + printf("Local recv alignment: %d\n",local_recv_align); + printf("Remote send alignment: %d\n",remote_send_align); + printf("Remote recv alignment: %d\n",remote_recv_align); + printf("Local socket priority: %d\n", local_socket_prio); + printf("Remote socket priority: %d\n", remote_socket_prio); + printf("Local socket TOS: %s\n", iptos2str(local_socket_tos)); + printf("Remote socket TOS: %s\n", iptos2str(remote_socket_tos)); + printf("Report local CPU %d\n",local_cpu_usage); + printf("Report remote CPU %d\n",remote_cpu_usage); + printf("Verbosity: %d\n",verbosity); + printf("Debug: %d\n",debug); + printf("Port: %s\n",test_port); + printf("Test name: %s\n",test_name); + printf("Test bytes: %d Test time: %d Test trans: %d\n", + test_bytes, + test_time, + test_trans); + printf("Host name: %s\n",host_name); + printf("\n"); +} |