aboutsummaryrefslogtreecommitdiff
path: root/src/nettest_omni.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nettest_omni.c')
-rw-r--r--src/nettest_omni.c7490
1 files changed, 7490 insertions, 0 deletions
diff --git a/src/nettest_omni.c b/src/nettest_omni.c
new file mode 100644
index 0000000..d4221a8
--- /dev/null
+++ b/src/nettest_omni.c
@@ -0,0 +1,7490 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WANT_OMNI
+char nettest_omni_id[]="\
+@(#)nettest_omni.c (c) Copyright 2008-2012 Hewlett-Packard Co. Version 2.6.0";
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#if HAVE_SCHED_H
+# include <sched.h>
+#endif
+
+#include <fcntl.h>
+#ifndef WIN32
+#include <errno.h>
+#include <signal.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <ctype.h>
+
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#endif /* NOSTDLIBH */
+
+#include <assert.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/* it would seem that including both <netinet/tcp.h> and <linux/tcp.h>
+ is not a path to happiness and joy when one wishes to grab tcp_info
+ stats and not get something like the compiler complaining about
+ either redefinitions, or missing tcpi_total_retrans. */
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#else
+#include <netinet/tcp.h>
+#endif
+
+/* this is to get us the definition of MSG_FASTOPEN. we may need to
+ cheat just a litle at first */
+#ifdef HAVE_LINUX_SOCKET_H
+# include <linux/socket.h>
+# ifndef MSG_FASTOPEN
+# warning Using our own value for MSG_FASTOPEN
+# define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */
+# endif
+# ifndef TCP_FASTOPEN
+# warning Using our own value for TCP_FASTOPEN
+# define TCP_FASTOPEN 23
+# endif
+#endif
+
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#else /* WIN32 */
+#include <process.h>
+#define netperf_socklen_t socklen_t
+#include <winsock2.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
+#include <windows.h>
+
+#define sleep(x) Sleep((x)*1000)
+
+#include "missing\stdint.h"
+#endif /* WIN32 */
+
+/* We don't want to use bare constants in the shutdown() call. In the
+ extremely unlikely event that SHUT_WR isn't defined, we will define
+ it to the value we used to be passing to shutdown() anyway. raj
+ 2007-02-08 */
+#if !defined(SHUT_WR)
+#define SHUT_WR 1
+#endif
+
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
+# include "missing/getaddrinfo.h"
+#endif
+
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_bsd.h"
+
+/* we only really use this once, but the initial patch to
+ src/nettest_bsd.c used it in several places. keep it as a macro
+ just for kicks and just in case we do end-up needing to use it
+ multiple times. */
+
+#define WAIT_BEFORE_DATA_TRAFFIC() \
+{ \
+ if (wait_time_secs) \
+ sleep(wait_time_secs); \
+} \
+
+
+/* since someone can ask for latency stats, we will always include
+ this and do the other other things */
+#include "hist.h"
+
+static HIST time_hist;
+
+
+
+#ifdef WANT_INTERVALS
+int interval_count;
+unsigned int interval_wait_microseconds;
+
+/* hoist the timestamps up here so we can use them to factor-out the
+ time spent "waiting" */
+/* first out timestamp */
+#ifdef HAVE_GETHRTIME
+static hrtime_t intvl_one;
+static hrtime_t intvl_two;
+static hrtime_t intvl_wait_start;
+static hrtime_t *intvl_one_ptr = &intvl_one;
+static hrtime_t *intvl_two_ptr = &intvl_two;
+static hrtime_t *temp_intvl_ptr = &intvl_one;
+#elif defined(WIN32)
+static LARGE_INTEGER intvl_one;
+static LARGE_INTEGER intvl_two;
+static LARGE_INTEGER intvl_wait_start;
+static LARGE_INTEGER *intvl_one_ptr = &intvl_one;
+static LARGE_INTEGER *intvl_two_ptr = &intvl_two;
+static LARGE_INTEGER *temp_intvl_ptr = &intvl_one;
+#else
+static struct timeval intvl_one;
+static struct timeval intvl_two;
+static struct timeval intvl_wait_start;
+static struct timeval *intvl_one_ptr = &intvl_one;
+static struct timeval *intvl_two_ptr = &intvl_two;
+static struct timeval *temp_intvl_ptr = &intvl_one;
+#endif
+
+#ifndef WANT_SPIN
+#ifdef WIN32
+#define INTERVALS_INIT() \
+ if (interval_burst) { \
+ /* zero means that we never pause, so we never should need the \
+ interval timer. we used to use it for demo mode, but we deal \
+ with that with a variant on watching the clock rather than \
+ waiting for a timer. raj 2006-02-06 */ \
+ start_itimer(interval_wate); \
+ } \
+ interval_count = interval_burst; \
+ interval_wait_microseconds = 0;
+#else
+sigset_t signal_set;
+#define INTERVALS_INIT() \
+ if (interval_burst) { \
+ /* zero means that we never pause, so we never should need the \
+ interval timer. we used to use it for demo mode, but we deal \
+ with that with a variant on watching the clock rather than \
+ waiting for a timer. raj 2006-02-06 */ \
+ start_itimer(interval_wate); \
+ } \
+ interval_count = interval_burst; \
+ interval_wait_microseconds = 0; \
+ /* get the signal set for the call to sigsuspend */ \
+ if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) { \
+ fprintf(where, \
+ "%s: unable to get sigmask errno %d\n", \
+ __FUNCTION__, \
+ errno); \
+ fflush(where); \
+ exit(1); \
+ }
+#endif /* WIN32 */
+
+#ifdef WIN32
+#define INTERVALS_WAIT() \
+ /* in this case, the interval count is the count-down counter \
+ to decide to sleep for a little bit */ \
+ if ((interval_burst) && (--interval_count == 0)) { \
+ /* call WaitForSingleObject and wait for the interval timer to get us \
+ out */ \
+ if (debug > 1) { \
+ fprintf(where,"about to suspend\n"); \
+ fflush(where); \
+ } \
+ HIST_timestamp(&intvl_wait_start); \
+ if (WaitForSingleObject(WinTimer, INFINITE) != WAIT_OBJECT_0) { \
+ fprintf(where, "WaitForSingleObject failed (%d)\n", GetLastError()); \
+ fflush(where); \
+ exit(1); \
+ } \
+ HIST_timestamp(&intvl_two); \
+ interval_wait_microseconds += \
+ delta_micro(&intvl_wait_start,&intvl_two); \
+ interval_count = interval_burst; \
+ }
+#else
+#define INTERVALS_WAIT() \
+ /* in this case, the interval count is the count-down couter \
+ to decide to sleep for a little bit */ \
+ if ((interval_burst) && (--interval_count == 0)) { \
+ /* call sigsuspend and wait for the interval timer to get us \
+ out */ \
+ if (debug > 1) { \
+ fprintf(where,"about to suspend\n"); \
+ fflush(where); \
+ } \
+ HIST_timestamp(&intvl_wait_start); \
+ if (sigsuspend(&signal_set) == EFAULT) { \
+ fprintf(where, \
+ "%s: fault with sigsuspend.\n", \
+ __FUNCTION__); \
+ fflush(where); \
+ exit(1); \
+ } \
+ HIST_timestamp(&intvl_two); \
+ interval_wait_microseconds += \
+ delta_micro(&intvl_wait_start,&intvl_two); \
+ interval_count = interval_burst; \
+ }
+#endif /* WIN32 */
+#else
+
+#define INTERVALS_INIT() \
+ if (interval_burst) { \
+ HIST_timestamp(intvl_one_ptr); \
+ } \
+ interval_wait_microseconds = 0; \
+ interval_count = interval_burst; \
+
+#define INTERVALS_WAIT() \
+ /* in this case, the interval count is the count-down couter \
+ to decide to sleep for a little bit */ \
+ if ((interval_burst) && (--interval_count == 0)) { \
+ /* spin and wait for the interval timer to get us \
+ out */ \
+ if (debug > 1) { \
+ fprintf(where,"about to spin suspend\n"); \
+ fflush(where); \
+ } \
+ \
+ HIST_timestamp(&intvl_wait_start); \
+ do { \
+ HIST_timestamp(intvl_two_ptr); } \
+ while(delta_micro(intvl_one_ptr,intvl_two_ptr) < interval_usecs); \
+ interval_wait_microseconds += \
+ delta_micro(&intvl_wait_start,&intvl_two); \
+ temp_intvl_ptr = intvl_one_ptr; \
+ intvl_one_ptr = intvl_two_ptr; \
+ intvl_two_ptr = temp_intvl_ptr; \
+ interval_count = interval_burst; \
+ }
+#endif
+#endif
+
+#define NETPERF_WAITALL 0x1
+
+extern void get_uuid_string(char *string, size_t size);
+
+/* a boatload of globals while I settle things out */
+char *output_selection_spec = NULL;
+
+char test_uuid[38];
+
+double result_confid_pct = -1.0;
+double loc_cpu_confid_pct = -1.0;
+double rem_cpu_confid_pct = -1.0;
+double interval_pct = -1.0;
+
+int protocol;
+int direction;
+int remote_send_size = -1;
+int remote_recv_size = -1;
+int remote_send_size_req = -1;
+int remote_recv_size_req = -1;
+int remote_use_sendfile;
+
+extern int loc_dirty_count;
+extern int loc_clean_count;
+extern int rem_dirty_count;
+extern int rem_clean_count;
+int remote_checksum_off;
+int connection_test;
+int dont_give_up = 0;
+int use_fastopen = 0;
+int use_write = 0;
+int need_to_connect;
+int need_connection;
+int bytes_to_send;
+double bytes_per_send;
+int failed_sends;
+int bytes_to_recv;
+double bytes_per_recv;
+int null_message_ok = 0;
+
+int was_legacy = 0;
+int legacy = 0;
+int implicit_direction = 0;
+int explicit_data_address = 0;
+int want_defer_accept = 0;
+
+uint64_t trans_completed = 0;
+int64_t units_remaining;
+uint64_t bytes_sent = 0;
+uint64_t bytes_received = 0;
+uint64_t local_send_calls = 0;
+uint64_t local_receive_calls = 0;
+uint64_t remote_bytes_sent;
+uint64_t remote_bytes_received;
+uint64_t remote_send_calls;
+uint64_t remote_receive_calls;
+double bytes_xferd;
+double remote_bytes_xferd;
+double remote_bytes_per_recv;
+double remote_bytes_per_send;
+float elapsed_time;
+float local_cpu_utilization;
+float local_service_demand;
+float remote_cpu_utilization;
+float remote_service_demand;
+double thruput;
+double local_send_thruput;
+double local_recv_thruput;
+double remote_send_thruput;
+double remote_recv_thruput;
+
+/* kludges for omni output */
+double elapsed_time_double;
+double local_service_demand_double;
+double remote_service_demand_double;
+double transaction_rate = 1.0;
+double rtt_latency = -1.0;
+int32_t transport_mss = -2;
+int32_t local_transport_retrans = -2;
+int32_t remote_transport_retrans = -2;
+char *deprecated_str = "Deprecated";
+int remote_interface_vendor = -2;
+int remote_interface_device = -2;
+int remote_interface_subvendor = -2;
+int remote_interface_subdevice = -2;
+int local_interface_vendor = -2;
+int local_interface_device = -2;
+int local_interface_subvendor = -2;
+int local_interface_subdevice = -2;
+int local_cpu_frequency = 0;
+int remote_cpu_frequency = 0;
+
+int local_security_type_id;
+int local_security_enabled_num;
+int remote_security_type_id;
+int remote_security_enabled_num;
+
+char local_cong_control[16] = "";
+char remote_cong_control[16] = "";
+char local_cong_control_req[16] = "";
+char remote_cong_control_req[16] = "";
+
+int receive_timeout = -1;
+
+/* new statistics based on code diffs from Google, with raj's own
+ personal twist added to make them compatible with the omni
+ tests... 20100913 */
+
+/* min and max "latency" */
+int min_latency = -1, max_latency = -1;
+/* the percentiles */
+int p50_latency = -1, p90_latency = -1, p99_latency = -1;
+/* mean and stddev - while the mean is reduntant with the *_RR test we
+ keep it because it won't be for other tests */
+double mean_latency = -1.0, stddev_latency = -1.0;
+
+/* default to zero to avoid randomizing */
+int local_mask_len = 0;
+int remote_mask_len = 0;
+
+int printing_initialized = 0;
+
+char *sd_str;
+char *thruput_format_str;
+
+char *socket_type_str;
+char *protocol_str;
+char *direction_str;
+
+extern int first_burst_size;
+
+int parallel_connections = 1;
+
+static int socket_debug = 0;
+
+#if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun))
+#include <sys/sendfile.h>
+#endif /* HAVE_SENDFILE && (__linux || __sun) */
+
+static int confidence_iteration;
+
+static int local_cpu_method;
+static int remote_cpu_method;
+
+/* these will control the width of port numbers we try to use in the */
+/* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
+static int client_port_min = 5000;
+static int client_port_max = 65535;
+
+ /* different options for the sockets */
+
+int
+ loc_nodelay, /* don't/do use NODELAY locally */
+ rem_nodelay, /* don't/do use NODELAY remotely */
+ loc_sndavoid, /* avoid send copies locally */
+ loc_rcvavoid, /* avoid recv copies locally */
+ rem_sndavoid, /* avoid send copies remotely */
+ rem_rcvavoid; /* avoid recv_copies remotely */
+
+extern int
+ loc_tcpcork,
+ rem_tcpcork,
+ local_connected,
+ remote_connected;
+
+enum netperf_output_type {
+ NETPERF_TYPE_UNKNOWN,
+ NETPERF_TYPE_UINT32,
+ NETPERF_TYPE_INT32,
+ NETPERF_TYPE_UINT64,
+ NETPERF_TYPE_INT64,
+ NETPERF_TYPE_CHAR,
+ NETPERF_TYPE_FLOAT,
+ NETPERF_TYPE_DOUBLE,
+};
+
+/* you should add to this in the order in which they should appear in
+ the default csv (everything) output */
+
+enum netperf_output_name {
+ NETPERF_OUTPUT_UNKNOWN,
+ OUTPUT_NONE,
+ SOCKET_TYPE,
+ PROTOCOL,
+ DIRECTION,
+ ELAPSED_TIME,
+ THROUGHPUT,
+ THROUGHPUT_UNITS,
+ LSS_SIZE_REQ,
+ LSS_SIZE,
+ LSS_SIZE_END,
+ LSR_SIZE_REQ,
+ LSR_SIZE,
+ LSR_SIZE_END,
+ RSS_SIZE_REQ,
+ RSS_SIZE,
+ RSS_SIZE_END,
+ RSR_SIZE_REQ,
+ RSR_SIZE,
+ RSR_SIZE_END,
+ LOCAL_SEND_SIZE,
+ LOCAL_RECV_SIZE,
+ REMOTE_SEND_SIZE,
+ REMOTE_RECV_SIZE,
+ REQUEST_SIZE,
+ RESPONSE_SIZE,
+ LOCAL_CPU_UTIL,
+ LOCAL_CPU_PERCENT_USER,
+ LOCAL_CPU_PERCENT_SYSTEM,
+ LOCAL_CPU_PERCENT_IOWAIT,
+ LOCAL_CPU_PERCENT_IRQ,
+ LOCAL_CPU_PERCENT_SWINTR,
+ LOCAL_CPU_METHOD,
+ LOCAL_SD,
+ REMOTE_CPU_UTIL,
+ REMOTE_CPU_PERCENT_USER,
+ REMOTE_CPU_PERCENT_SYSTEM,
+ REMOTE_CPU_PERCENT_IOWAIT,
+ REMOTE_CPU_PERCENT_IRQ,
+ REMOTE_CPU_PERCENT_SWINTR,
+ REMOTE_CPU_METHOD,
+ REMOTE_SD,
+ SD_UNITS,
+ CONFIDENCE_LEVEL,
+ CONFIDENCE_INTERVAL,
+ CONFIDENCE_ITERATION,
+ THROUGHPUT_CONFID,
+ LOCAL_CPU_CONFID,
+ REMOTE_CPU_CONFID,
+ TRANSACTION_RATE,
+ RT_LATENCY,
+ BURST_SIZE,
+ LOCAL_TRANSPORT_RETRANS,
+ REMOTE_TRANSPORT_RETRANS,
+ TRANSPORT_MSS,
+ LOCAL_SEND_THROUGHPUT,
+ LOCAL_RECV_THROUGHPUT,
+ REMOTE_SEND_THROUGHPUT,
+ REMOTE_RECV_THROUGHPUT,
+ LOCAL_CPU_BIND,
+ LOCAL_CPU_COUNT,
+ LOCAL_CPU_PEAK_UTIL,
+ LOCAL_CPU_PEAK_ID,
+ LOCAL_CPU_MODEL,
+ LOCAL_CPU_FREQUENCY,
+ REMOTE_CPU_BIND,
+ REMOTE_CPU_COUNT,
+ REMOTE_CPU_PEAK_UTIL,
+ REMOTE_CPU_PEAK_ID,
+ REMOTE_CPU_MODEL,
+ REMOTE_CPU_FREQUENCY,
+ SOURCE_PORT,
+ SOURCE_ADDR,
+ SOURCE_FAMILY,
+ DEST_PORT,
+ DEST_ADDR,
+ DEST_FAMILY,
+ LOCAL_SEND_CALLS,
+ LOCAL_RECV_CALLS,
+ LOCAL_BYTES_PER_RECV,
+ LOCAL_BYTES_PER_SEND,
+ LOCAL_BYTES_SENT,
+ LOCAL_BYTES_RECVD,
+ LOCAL_BYTES_XFERD,
+ LOCAL_SEND_OFFSET,
+ LOCAL_RECV_OFFSET,
+ LOCAL_SEND_ALIGN,
+ LOCAL_RECV_ALIGN,
+ LOCAL_SEND_WIDTH,
+ LOCAL_RECV_WIDTH,
+ LOCAL_SEND_DIRTY_COUNT,
+ LOCAL_RECV_DIRTY_COUNT,
+ LOCAL_RECV_CLEAN_COUNT,
+ LOCAL_NODELAY,
+ LOCAL_CORK,
+ REMOTE_SEND_CALLS,
+ REMOTE_RECV_CALLS,
+ REMOTE_BYTES_PER_RECV,
+ REMOTE_BYTES_PER_SEND,
+ REMOTE_BYTES_SENT,
+ REMOTE_BYTES_RECVD,
+ REMOTE_BYTES_XFERD,
+ REMOTE_SEND_OFFSET,
+ REMOTE_RECV_OFFSET,
+ REMOTE_SEND_ALIGN,
+ REMOTE_RECV_ALIGN,
+ REMOTE_SEND_WIDTH,
+ REMOTE_RECV_WIDTH,
+ REMOTE_SEND_DIRTY_COUNT,
+ REMOTE_RECV_DIRTY_COUNT,
+ REMOTE_RECV_CLEAN_COUNT,
+ REMOTE_NODELAY,
+ REMOTE_CORK,
+ LOCAL_SYSNAME,
+ LOCAL_SYSTEM_MODEL,
+ LOCAL_RELEASE,
+ LOCAL_VERSION,
+ LOCAL_MACHINE,
+ REMOTE_SYSNAME,
+ REMOTE_SYSTEM_MODEL,
+ REMOTE_RELEASE,
+ REMOTE_VERSION,
+ REMOTE_MACHINE,
+ LOCAL_INTERFACE_NAME,
+ LOCAL_INTERFACE_VENDOR,
+ LOCAL_INTERFACE_DEVICE,
+ LOCAL_INTERFACE_SUBVENDOR,
+ LOCAL_INTERFACE_SUBDEVICE,
+ LOCAL_DRIVER_NAME,
+ LOCAL_DRIVER_VERSION,
+ LOCAL_DRIVER_FIRMWARE,
+ LOCAL_DRIVER_BUS,
+ LOCAL_INTERFACE_SLOT,
+ REMOTE_INTERFACE_NAME,
+ REMOTE_INTERFACE_VENDOR,
+ REMOTE_INTERFACE_DEVICE,
+ REMOTE_INTERFACE_SUBVENDOR,
+ REMOTE_INTERFACE_SUBDEVICE,
+ REMOTE_DRIVER_NAME,
+ REMOTE_DRIVER_VERSION,
+ REMOTE_DRIVER_FIRMWARE,
+ REMOTE_DRIVER_BUS,
+ REMOTE_INTERFACE_SLOT,
+ LOCAL_INTERVAL_USECS,
+ LOCAL_INTERVAL_BURST,
+ REMOTE_INTERVAL_USECS,
+ REMOTE_INTERVAL_BURST,
+ LOCAL_SECURITY_TYPE_ID,
+ LOCAL_SECURITY_TYPE,
+ LOCAL_SECURITY_ENABLED_NUM,
+ LOCAL_SECURITY_ENABLED,
+ LOCAL_SECURITY_SPECIFIC,
+ REMOTE_SECURITY_TYPE_ID,
+ REMOTE_SECURITY_TYPE,
+ REMOTE_SECURITY_ENABLED_NUM,
+ REMOTE_SECURITY_ENABLED,
+ REMOTE_SECURITY_SPECIFIC,
+ RESULT_BRAND,
+ UUID,
+ MIN_LATENCY,
+ MAX_LATENCY,
+ P50_LATENCY,
+ P90_LATENCY,
+ P99_LATENCY,
+ MEAN_LATENCY,
+ STDDEV_LATENCY,
+ LOCAL_SOCKET_PRIO,
+ REMOTE_SOCKET_PRIO,
+ LOCAL_SOCKET_TOS,
+ REMOTE_SOCKET_TOS,
+ LOCAL_CONG_CONTROL,
+ REMOTE_CONG_CONTROL,
+ LOCAL_FILL_FILE,
+ REMOTE_FILL_FILE,
+ COMMAND_LINE, /* COMMAND_LINE should always be "last" */
+ OUTPUT_END,
+ NETPERF_OUTPUT_MAX
+};
+
+/* flags for the output groups, lower 16 bits for remote, upper 16
+ bits for local */
+
+#define OMNI_WANT_REM_IFNAME 0X00000001
+#define OMNI_WANT_LOC_IFNAME 0X00010000
+#define OMNI_WANT_REM_IFSLOT 0X00000002
+#define OMNI_WANT_LOC_IFSLOT 0X00020000
+#define OMNI_WANT_REM_IFIDS 0X00000004
+#define OMNI_WANT_LOC_IFIDS 0X00040000
+#define OMNI_WANT_REM_DRVINFO 0X00000008
+#define OMNI_WANT_LOC_DRVINFO 0X00080000
+#define OMNI_WANT_STATS 0X00100010
+#define OMNI_WANT_REM_CONG 0X00000020
+#define OMNI_WANT_LOC_CONG 0X00200000
+
+unsigned int desired_output_groups = 0;
+
+typedef struct netperf_output_elt {
+ enum netperf_output_name output_name; /* belt and suspenders */
+ int max_line_len; /* length of the longest of the "lines" */
+ int tot_line_len; /* total length of all lines, including spaces */
+ char *line[4];
+ char *format; /* format to apply to value */
+ void *display_value; /* where to find the value */
+ enum netperf_output_type output_type; /* what type is the value? */
+ int output_default; /* is it included in the default output */
+ unsigned int output_group; /* used to avoid some lookups */
+} netperf_output_elt_t;
+
+netperf_output_elt_t netperf_output_source[NETPERF_OUTPUT_MAX];
+
+#define NETPERF_MAX_BLOCKS 4
+
+/* let us simply use one, two-dimensional list, and either use or some
+ of the additional dimension depending on the type of output we are
+ doing. this should help simplify matters. raj 20110120 */
+
+enum netperf_output_name output_list[NETPERF_MAX_BLOCKS][NETPERF_OUTPUT_MAX];
+
+/* some things for setting the source IP address on outgoing UDP
+ sends. borrows liberally from
+ http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket */
+
+int want_use_pktinfo = 0;
+int use_pktinfo = 0;
+int have_pktinfo = 0;
+#ifdef IP_PKTINFO
+struct in_pktinfo in_pktinfo;
+#endif
+
+char *direction_to_str(int direction) {
+ if (NETPERF_RECV_ONLY(direction)) return "Receive";
+ if (NETPERF_XMIT_ONLY(direction)) return "Send";
+ if (NETPERF_CC(direction)) return "Connection";
+ else if (connection_test) {
+ return "Connect|Send|Recv";
+ }
+ else return "Send|Recv";
+}
+
+static unsigned short
+get_port_number(struct addrinfo *res)
+{
+ switch(res->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
+ return(ntohs(foo->sin_port));
+ break;
+ }
+#if defined(AF_INET6)
+ case AF_INET6: {
+ struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
+ return(ntohs(foo->sin6_port));
+ break;
+ }
+#endif
+ default:
+ fprintf(where,
+ "Unexpected Address Family %u\n",res->ai_family);
+ fflush(where);
+ exit(-1);
+ }
+}
+
+/* does this need to become conditional on the presence of the macros
+ or might we ass-u-me that we will not be compiled on something so
+ old as to not have what we use? raj 20090803 */
+static int
+is_multicast_addr(struct addrinfo *res) {
+ switch(res->ai_family) {
+ case AF_INET: {
+ /* IPv4 multicast runs from 224.0.0.0 to 239.255.255.255 or
+ 0xE0000000 to 0xEFFFFFFF. Thankfully though there are macros
+ available to make the checks for one */
+ struct in_addr bar = ((struct sockaddr_in *)res->ai_addr)->sin_addr;
+ /* and here I thought IN_MULTICAST would operate on things in
+ network byte order??? raj 20100315 */
+ return IN_MULTICAST(ntohl(bar.s_addr));
+ }
+#if defined(AF_INET6)
+ case AF_INET6: {
+ struct in6_addr *bar = &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr);
+ return IN6_IS_ADDR_MULTICAST(bar);
+ }
+#endif
+ default:
+ fprintf(where,
+ "Unexpected Address Family for Multicast Check %u\n",
+ res->ai_family);
+ fflush(where);
+ return 0; /* or should we exit? */
+ }
+}
+
+static void
+set_multicast_ttl(SOCKET sock) {
+ int optlen = sizeof(int);
+
+ /* now set/get the TTL */
+ if (multicast_ttl >= 0) {
+ if (setsockopt(sock,
+ IPPROTO_IP,
+#if defined(IP_MULTICAST_TTL)
+ IP_MULTICAST_TTL,
+#else
+ IP_TTL,
+#endif
+ (const char *)&multicast_ttl,
+ sizeof(multicast_ttl)) == SOCKET_ERROR) {
+ fprintf(where,
+ "setsockopt(IP_TTL) failed errno %d\n",
+ errno);
+ }
+ }
+ if (getsockopt(sock,
+ IPPROTO_IP,
+ IP_TTL,
+ (char *)&multicast_ttl,
+ (netperf_socklen_t *)&optlen) < 0) {
+ fprintf(where,
+ "getsockopt(IP_TTL) failed errno %d\n",
+ errno);
+ multicast_ttl = -2;
+ }
+}
+
+/* we presume we are only called with something which is actually a
+ multicast address. raj 20100315 */
+static void
+join_multicast_addr(SOCKET sock, struct addrinfo *res) {
+ switch(res->ai_family) {
+ case AF_INET: {
+ struct ip_mreq mreq;
+ struct in_addr bar = ((struct sockaddr_in *)res->ai_addr)->sin_addr;
+ int optlen = sizeof(int);
+ int one = 1;
+
+ mreq.imr_multiaddr.s_addr=bar.s_addr;
+ mreq.imr_interface.s_addr=htonl(INADDR_ANY);
+ if (setsockopt(sock,
+ IPPROTO_IP,
+ IP_ADD_MEMBERSHIP,
+ (const char *)&mreq,
+ sizeof(mreq)) == 0) {
+
+ /* let others do the same */
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (const char *)&one,
+ sizeof(one)) == SOCKET_ERROR) {
+ if (debug) {
+ fprintf(where,
+ "join_multicast_addr SO_REUSADDR failed errno %d\n",
+ errno);
+ fflush(where);
+ }
+ }
+
+ /* now set/get the TTL */
+ if (multicast_ttl >= 0) {
+ if (setsockopt(sock,
+ IPPROTO_IP,
+ IP_TTL,
+ (const char *)&multicast_ttl,
+ sizeof(multicast_ttl)) == SOCKET_ERROR) {
+ fprintf(where,
+ "setsockopt(IP_TTL) failed errno %d\n",
+ errno);
+ }
+ }
+ if (getsockopt(sock,
+ IPPROTO_IP,
+ IP_TTL,
+ (char *)&multicast_ttl,
+ (netperf_socklen_t *)&optlen) == SOCKET_ERROR) {
+ fprintf(where,
+ "getsockopt(IP_TTL) failed errno %d\n",
+ errno);
+ multicast_ttl = -2;
+ }
+ }
+ else {
+ if (debug) {
+ fprintf(where,
+ "setsockopt(IP_ADD_MEMBERSHIP) failed errno %d\n",
+ errno);
+ fflush(where);
+ }
+ }
+ break;
+ }
+ case AF_INET6: {
+ fprintf(where,"I do not know how to join an IPv6 multicast group\n");
+ break;
+ }
+
+ }
+ return;
+}
+
+static void
+extract_inet_address_and_port(struct addrinfo *res, void *addr, int len, int *port)
+{
+ switch(res->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
+ *port = foo->sin_port;
+ memcpy(addr,&(foo->sin_addr),min(len,sizeof(foo->sin_addr)));
+ break;
+ }
+#if defined(AF_INET6)
+ case AF_INET6: {
+ struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
+ *port = foo->sin6_port;
+ memcpy(addr,&(foo->sin6_addr),min(len,sizeof(foo->sin6_addr)));
+ break;
+ }
+#endif
+ default:
+ *port = 0xDEADBEEF;
+ strncpy(addr,"UNKN FAMILY",len);
+ }
+}
+
+void
+pick_next_port_number(struct addrinfo *local_res, struct addrinfo *remote_res) {
+
+ static int myport_init = 0;
+ static unsigned short myport = 0;
+
+ if (0 == myport_init) {
+ /* pick a nice random spot between client_port_min and
+ client_port_max for our initial port number, but only for a
+ connection oriented test. otherwise, we will want to set myport
+ to a specific port provided by the user if they have so provided
+ a specific port :) raj 2008-01-08 */
+ srand(getpid());
+ if (client_port_max - client_port_min) {
+ myport = client_port_min +
+ (rand() % (client_port_max - client_port_min));
+ }
+ else {
+ myport = (unsigned short)client_port_min;
+ }
+ /* there will be a ++ before the first call to bind, so subtract one */
+ myport--;
+ myport_init = 1;
+ }
+
+ /* newport: */
+ /* pick a new port number */
+ myport++;
+
+ /* check to see if we are using the port number on which the
+ server is sitting _before_ we check against the boundaries lest
+ the server sits at the upper boundary. if this happens to be a
+ loopback test, trying to use the same portnumber would lead to
+ unsatisfying results and should be avoided. if this isn't a
+ loopback test, avoiding using the same port number doesn't
+ seriously affect anything anyway */
+
+ if (myport == get_port_number(remote_res)) myport++;
+
+ /* wrap the port number when we reach the upper bound. for
+ students of networking history, some ancient stacks (1980's and
+ early 1990's perhaps) mistakenly treated these port numbers as
+ signed 16 bit quantities. we make no effort here to support
+ such stacks. raj 2008-01-08 */
+ if (myport >= client_port_max) {
+ myport = (unsigned short)client_port_min;
+ }
+
+ /* set up the data socket */
+ set_port_number(local_res, (unsigned short)myport);
+}
+
+/* at some point this should become a table lookup... raj 20090813 */
+char *
+netperf_output_enum_to_str(enum netperf_output_name output_name)
+{
+ switch (output_name) {
+ case OUTPUT_NONE:
+ return "OUTPUT_NONE";
+ case COMMAND_LINE:
+ return "COMMAND_LINE";
+ case UUID:
+ return "UUID";
+ case RESULT_BRAND:
+ return "RESULT_BRAND";
+ case SOCKET_TYPE:
+ return "SOCKET_TYPE";
+ case DIRECTION:
+ return "DIRECTION";
+ case PROTOCOL:
+ return "PROTOCOL";
+ case ELAPSED_TIME:
+ return "ELAPSED_TIME";
+ case SOURCE_PORT:
+ return "SOURCE_PORT";
+ case SOURCE_ADDR:
+ return "SOURCE_ADDR";
+ case SOURCE_FAMILY:
+ return "SOURCE_FAMILY";
+ case DEST_PORT:
+ return "DEST_PORT";
+ case DEST_ADDR:
+ return "DEST_ADDR";
+ case DEST_FAMILY:
+ return "DEST_FAMILY";
+ case THROUGHPUT:
+ return "THROUGHPUT";
+ case LOCAL_SEND_THROUGHPUT:
+ return "LOCAL_SEND_THROUGHPUT";
+ case LOCAL_RECV_THROUGHPUT:
+ return "LOCAL_RECV_THROUGHPUT";
+ case REMOTE_SEND_THROUGHPUT:
+ return "REMOTE_SEND_THROUGHPUT";
+ case REMOTE_RECV_THROUGHPUT:
+ return "REMOTE_RECV_THROUGHPUT";
+ case THROUGHPUT_UNITS:
+ return "THROUGHPUT_UNITS";
+ case CONFIDENCE_LEVEL:
+ return "CONFIDENCE_LEVEL";
+ case CONFIDENCE_INTERVAL:
+ return "CONFIDENCE_INTERVAL";
+ case CONFIDENCE_ITERATION:
+ return "CONFIDENCE_ITERATION";
+ case THROUGHPUT_CONFID:
+ return "THROUGHPUT_CONFID";
+ case LOCAL_CPU_CONFID:
+ return "LOCAL_CPU_CONFID";
+ case REMOTE_CPU_CONFID:
+ return "REMOTE_CPU_CONFID";
+ case RT_LATENCY:
+ return "RT_LATENCY";
+ case TRANSACTION_RATE:
+ return "TRANSACTION_RATE";
+ case BURST_SIZE:
+ return "BURST_SIZE";
+ case LOCAL_TRANSPORT_RETRANS:
+ return "LOCAL_TRANSPORT_RETRANS";
+ case REMOTE_TRANSPORT_RETRANS:
+ return "REMOTE_TRANSPORT_RETRANS";
+ case TRANSPORT_MSS:
+ return "TRANSPORT_MSS";
+ case REQUEST_SIZE:
+ return "REQUEST_SIZE";
+ case RESPONSE_SIZE:
+ return "RESPONSE_SIZE";
+ case LSS_SIZE_REQ:
+ return "LSS_SIZE_REQ";
+ case LSS_SIZE:
+ return "LSS_SIZE";
+ case LSS_SIZE_END:
+ return "LSS_SIZE_END";
+ case LSR_SIZE_REQ:
+ return "LSR_SIZE_REQ";
+ case LSR_SIZE:
+ return "LSR_SIZE";
+ case LSR_SIZE_END:
+ return "LSR_SIZE_END";
+ case LOCAL_SEND_SIZE:
+ return "LOCAL_SEND_SIZE";
+ case LOCAL_RECV_SIZE:
+ return "LOCAL_RECV_SIZE";
+ case LOCAL_SEND_CALLS:
+ return "LOCAL_SEND_CALLS";
+ case LOCAL_RECV_CALLS:
+ return "LOCAL_RECV_CALLS";
+ case LOCAL_BYTES_PER_RECV:
+ return "LOCAL_BYTES_PER_RECV";
+ case LOCAL_BYTES_PER_SEND:
+ return "LOCAL_BYTES_PER_SEND";
+ case LOCAL_BYTES_SENT:
+ return "LOCAL_BYTES_SENT";
+ case LOCAL_BYTES_RECVD:
+ return "LOCAL_BYTES_RECVD";
+ case LOCAL_BYTES_XFERD:
+ return "LOCAL_BYTES_XFERD";
+ case LOCAL_SEND_OFFSET:
+ return "LOCAL_SEND_OFFSET";
+ case LOCAL_RECV_OFFSET:
+ return "LOCAL_RECV_OFFSET";
+ case LOCAL_RECV_ALIGN:
+ return "LOCAL_RECV_ALIGN";
+ case LOCAL_SEND_ALIGN:
+ return "LOCAL_SEND_ALIGN";
+ case LOCAL_SEND_WIDTH:
+ return "LOCAL_SEND_WIDTH";
+ case LOCAL_RECV_WIDTH:
+ return "LOCAL_RECV_WIDTH";
+ case LOCAL_SEND_DIRTY_COUNT:
+ return "LOCAL_SEND_DIRTY_COUNT";
+ case LOCAL_RECV_DIRTY_COUNT:
+ return "LOCAL_RECV_DIRTY_COUNT";
+ case LOCAL_RECV_CLEAN_COUNT:
+ return "LOCAL_RECV_CLEAN_COUNT";
+ case LOCAL_CPU_UTIL:
+ return "LOCAL_CPU_UTIL";
+ case LOCAL_CPU_PERCENT_USER:
+ return "LOCAL_CPU_PERCENT_USER";
+ case LOCAL_CPU_PERCENT_SYSTEM:
+ return "LOCAL_CPU_PERCENT_SYSTEM";
+ case LOCAL_CPU_PERCENT_IOWAIT:
+ return "LOCAL_CPU_PERCENT_IOWAIT";
+ case LOCAL_CPU_PERCENT_IRQ:
+ return "LOCAL_CPU_PERCENT_IRQ";
+ case LOCAL_CPU_PERCENT_SWINTR:
+ return "LOCAL_CPU_PERCENT_SWINTR";
+ case LOCAL_CPU_BIND:
+ return "LOCAL_CPU_BIND";
+ case LOCAL_SD:
+ return "LOCAL_SD";
+ case SD_UNITS:
+ return "SD_UNITS";
+ case LOCAL_CPU_METHOD:
+ return "LOCAL_CPU_METHOD";
+ case LOCAL_CPU_COUNT:
+ return "LOCAL_CPU_COUNT";
+ case LOCAL_CPU_PEAK_UTIL:
+ return "LOCAL_CPU_PEAK_UTIL";
+ case LOCAL_CPU_PEAK_ID:
+ return "LOCAL_CPU_PEAK_ID";
+ case LOCAL_NODELAY:
+ return "LOCAL_NODELAY";
+ case LOCAL_CORK:
+ return "LOCAL_CORK";
+ case RSS_SIZE_REQ:
+ return "RSS_SIZE_REQ";
+ case RSS_SIZE:
+ return "RSS_SIZE";
+ case RSS_SIZE_END:
+ return "RSS_SIZE_END";
+ case RSR_SIZE_REQ:
+ return "RSR_SIZE_REQ";
+ case RSR_SIZE:
+ return "RSR_SIZE";
+ case RSR_SIZE_END:
+ return "RSR_SIZE_END";
+ case REMOTE_SEND_SIZE:
+ return "REMOTE_SEND_SIZE";
+ case REMOTE_RECV_SIZE:
+ return "REMOTE_RECV_SIZE";
+ case REMOTE_SEND_CALLS:
+ return "REMOTE_SEND_CALLS";
+ case REMOTE_RECV_CALLS:
+ return "REMOTE_RECV_CALLS";
+ case REMOTE_BYTES_PER_RECV:
+ return "REMOTE_BYTES_PER_RECV";
+ case REMOTE_BYTES_PER_SEND:
+ return "REMOTE_BYTES_PER_SEND";
+ case REMOTE_BYTES_SENT:
+ return "REMOTE_BYTES_SENT";
+ case REMOTE_BYTES_RECVD:
+ return "REMOTE_BYTES_RECVD";
+ case REMOTE_BYTES_XFERD:
+ return "REMOTE_BYTES_XFERD";
+ case REMOTE_SEND_OFFSET:
+ return "REMOTE_SEND_OFFSET";
+ case REMOTE_RECV_OFFSET:
+ return "REMOTE_RECV_OFFSET";
+ case REMOTE_RECV_ALIGN:
+ return "REMOTE_RECV_ALIGN";
+ case REMOTE_SEND_ALIGN:
+ return "REMOTE_SEND_ALIGN";
+ case REMOTE_SEND_WIDTH:
+ return "REMOTE_SEND_WIDTH";
+ case REMOTE_RECV_WIDTH:
+ return "REMOTE_RECV_WIDTH";
+ case REMOTE_SEND_DIRTY_COUNT:
+ return "REMOTE_SEND_DIRTY_COUNT";
+ case REMOTE_RECV_DIRTY_COUNT:
+ return "REMOTE_RECV_DIRTY_COUNT";
+ case REMOTE_RECV_CLEAN_COUNT:
+ return "REMOTE_RECV_CLEAN_COUNT";
+ case REMOTE_CPU_UTIL:
+ return "REMOTE_CPU_UTIL";
+ case REMOTE_CPU_PERCENT_USER:
+ return "REMOTE_CPU_PERCENT_USER";
+ case REMOTE_CPU_PERCENT_SYSTEM:
+ return "REMOTE_CPU_PERCENT_SYSTEM";
+ case REMOTE_CPU_PERCENT_IOWAIT:
+ return "REMOTE_CPU_PERCENT_IOWAIT";
+ case REMOTE_CPU_PERCENT_IRQ:
+ return "REMOTE_CPU_PERCENT_IRQ";
+ case REMOTE_CPU_PERCENT_SWINTR:
+ return "REMOTE_CPU_PERCENT_SWINTR";
+ case REMOTE_CPU_BIND:
+ return "REMOTE_CPU_BIND";
+ case REMOTE_SD:
+ return "REMOTE_SD";
+ case REMOTE_CPU_METHOD:
+ return "REMOTE_CPU_METHOD";
+ case REMOTE_CPU_COUNT:
+ return "REMOTE_CPU_COUNT";
+ case REMOTE_CPU_PEAK_UTIL:
+ return "REMOTE_CPU_PEAK_UTIL";
+ case REMOTE_CPU_PEAK_ID:
+ return "REMOTE_CPU_PEAK_ID";
+ case REMOTE_NODELAY:
+ return "REMOTE_NODELAY";
+ case REMOTE_CORK:
+ return "REMOTE_CORK";
+ case LOCAL_INTERFACE_SLOT:
+ return "LOCAL_INTERFACE_SLOT";
+ case REMOTE_INTERFACE_SLOT:
+ return "REMOTE_INTERFACE_SLOT";
+ case REMOTE_INTERFACE_SUBDEVICE:
+ return "REMOTE_INTERFACE_SUBDEVICE";
+ case REMOTE_INTERFACE_SUBVENDOR:
+ return "REMOTE_INTERFACE_SUBVENDOR";
+ case REMOTE_INTERFACE_DEVICE:
+ return "REMOTE_INTERFACE_DEVICE";
+ case REMOTE_INTERFACE_VENDOR:
+ return "REMOTE_INTERFACE_VENDOR";
+ case LOCAL_INTERFACE_SUBDEVICE:
+ return "LOCAL_INTERFACE_SUBDEVICE";
+ case LOCAL_INTERFACE_SUBVENDOR:
+ return "LOCAL_INTERFACE_SUBVENDOR";
+ case LOCAL_INTERFACE_DEVICE:
+ return "LOCAL_INTERFACE_DEVICE";
+ case LOCAL_INTERFACE_VENDOR:
+ return "LOCAL_INTERFACE_VENDOR";
+ case LOCAL_INTERFACE_NAME:
+ return "LOCAL_INTERFACE_NAME";
+ case REMOTE_INTERFACE_NAME:
+ return "REMOTE_INTERFACE_NAME";
+ case REMOTE_DRIVER_NAME:
+ return "REMOTE_DRIVER_NAME";
+ case REMOTE_DRIVER_VERSION:
+ return "REMOTE_DRIVER_VERSION";
+ case REMOTE_DRIVER_FIRMWARE:
+ return "REMOTE_DRIVER_FIRMWARE";
+ case REMOTE_DRIVER_BUS:
+ return "REMOTE_DRIVER_BUS";
+ case LOCAL_DRIVER_NAME:
+ return "LOCAL_DRIVER_NAME";
+ case LOCAL_DRIVER_VERSION:
+ return "LOCAL_DRIVER_VERSION";
+ case LOCAL_DRIVER_FIRMWARE:
+ return "LOCAL_DRIVER_FIRMWARE";
+ case LOCAL_INTERVAL_USECS:
+ return "LOCAL_INTERVAL_USECS";
+ case LOCAL_INTERVAL_BURST:
+ return "LOCAL_INTERVAL_BURST";
+ case REMOTE_INTERVAL_USECS:
+ return "REMOTE_INTERVAL_USECS";
+ case REMOTE_INTERVAL_BURST:
+ return "REMOTE_INTERVAL_BURST";
+ case LOCAL_SECURITY_TYPE_ID:
+ return "LOCAL_SECURITY_TYPE_ID";
+ case LOCAL_SECURITY_ENABLED_NUM:
+ return "LOCAL_SECURITY_ENABLED_NUM";
+ case LOCAL_SECURITY_TYPE:
+ return "LOCAL_SECURITY_TYPE";
+ case LOCAL_SECURITY_ENABLED:
+ return "LOCAL_SECURITY_ENABLED";
+ case LOCAL_SECURITY_SPECIFIC:
+ return "LOCAL_SECURITY_SPECIFIC";
+ case REMOTE_SECURITY_TYPE_ID:
+ return "REMOTE_SECURITY_TYPE_ID";
+ case REMOTE_SECURITY_ENABLED_NUM:
+ return "REMOTE_SECURITY_ENABLED_NUM";
+ case REMOTE_SECURITY_TYPE:
+ return "REMOTE_SECURITY_TYPE";
+ case REMOTE_SECURITY_ENABLED:
+ return "REMOTE_SECURITY_ENABLED";
+ case REMOTE_SECURITY_SPECIFIC:
+ return "REMOTE_SECURITY_SPECIFIC";
+ case LOCAL_DRIVER_BUS:
+ return "LOCAL_DRIVER_BUS";
+ case REMOTE_SYSNAME:
+ return "REMOTE_SYSNAME";
+ case REMOTE_MACHINE:
+ return "REMOTE_MACHINE";
+ case REMOTE_VERSION:
+ return "REMOTE_VERSION";
+ case REMOTE_RELEASE:
+ return "REMOTE_RELEASE";
+ case LOCAL_SYSNAME:
+ return "LOCAL_SYSNAME";
+ case LOCAL_MACHINE:
+ return "LOCAL_MACHINE";
+ case LOCAL_VERSION:
+ return "LOCAL_VERSION";
+ case LOCAL_RELEASE:
+ return "LOCAL_RELEASE";
+ case REMOTE_CPU_MODEL:
+ return "REMOTE_CPU_MODEL";
+ case REMOTE_CPU_FREQUENCY:
+ return "REMOTE_CPU_FREQUENCY";
+ case REMOTE_SYSTEM_MODEL:
+ return "REMOTE_SYSTEM_MODEL";
+ case LOCAL_CPU_MODEL:
+ return "LOCAL_CPU_MODEL";
+ case LOCAL_CPU_FREQUENCY:
+ return "LOCAL_CPU_FREQUENCY";
+ case LOCAL_SYSTEM_MODEL:
+ return "LOCAL_SYSTEM_MODEL";
+ case MIN_LATENCY:
+ return "MIN_LATENCY";
+ case MAX_LATENCY:
+ return "MAX_LATENCY";
+ case P50_LATENCY:
+ return "P50_LATENCY";
+ case P90_LATENCY:
+ return "P90_LATENCY";
+ case P99_LATENCY:
+ return "P99_LATENCY";
+ case MEAN_LATENCY:
+ return "MEAN_LATENCY";
+ case STDDEV_LATENCY:
+ return "STDDEV_LATENCY";
+ case LOCAL_SOCKET_PRIO:
+ return "LOCAL_SOCKET_PRIO";
+ case REMOTE_SOCKET_PRIO:
+ return "REMOTE_SOCKET_PRIO";
+ case LOCAL_SOCKET_TOS:
+ return "LOCAL_SOCKET_TOS";
+ case REMOTE_SOCKET_TOS:
+ return "REMOTE_SOCKET_TOS";
+ case LOCAL_CONG_CONTROL:
+ return "LOCAL_CONG_CONTROL";
+ case REMOTE_CONG_CONTROL:
+ return "REMOTE_CONG_CONTROL";
+ case LOCAL_FILL_FILE:
+ return "LOCAL_FILL_FILE";
+ case REMOTE_FILL_FILE:
+ return "REMOTE_FILL_FILE";
+ case OUTPUT_END:
+ return "OUTPUT_END";
+ default:
+ return "!UNKNOWN OUTPUT SELECTOR!";
+ }
+}
+
+void
+print_netperf_output_entry(FILE *where, enum netperf_output_name what)
+{
+}
+
+void print_omni_init_list();
+
+void
+dump_netperf_output_list(FILE *where) {
+
+ int i,j;
+
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ fprintf(where,"Output Block %d\n",i + 1);
+ for (j = 0; j < NETPERF_OUTPUT_MAX; j++) {
+ fprintf(where,"%s ",netperf_output_enum_to_str(output_list[i][j]));
+ }
+ fprintf(where,"\n");
+ }
+ fflush(where);
+}
+
+void
+dump_netperf_output_choices(FILE *where, int csv) {
+ int i;
+
+ print_omni_init_list();
+
+ for (i = OUTPUT_NONE; i < NETPERF_OUTPUT_MAX; i++){
+ if (OUTPUT_NONE != i) {
+ fprintf(where,"%c",(csv) ? ',' : '\n');
+ }
+ fprintf(where,
+ "%s",
+ netperf_output_enum_to_str(netperf_output_source[i].output_name));
+ }
+ fprintf(where,"\n");
+ fflush(where);
+}
+
+void
+dump_netperf_output_source(FILE *where)
+{
+ int i;
+
+ /* belts and suspenders everyone... */
+ for (i = OUTPUT_NONE; i < NETPERF_OUTPUT_MAX; i++) {
+ fprintf(where,
+ "Output Name: %s\n"
+ "\tmax_line_len %d tot_line_len %d display_value %p\n"
+ "\tline[0]: |%s|\n"
+ "\tline[1]: |%s|\n"
+ "\tline[2]: |%s|\n"
+ "\tline[3]: |%s|\n"
+ "\tformat: |%s|\n",
+ netperf_output_enum_to_str(netperf_output_source[i].output_name),
+ netperf_output_source[i].max_line_len,
+ netperf_output_source[i].tot_line_len,
+ netperf_output_source[i].display_value,
+ (netperf_output_source[i].line[0] == NULL) ? "" :
+ netperf_output_source[i].line[0],
+ (netperf_output_source[i].line[1] == NULL) ? "" :
+ netperf_output_source[i].line[1],
+ (netperf_output_source[i].line[2] == NULL) ? "" :
+ netperf_output_source[i].line[2],
+ (netperf_output_source[i].line[3] == NULL) ? "" :
+ netperf_output_source[i].line[3],
+ (netperf_output_source[i].format == NULL) ? "" :
+ netperf_output_source[i].format);
+ }
+ fflush(where);
+}
+
+#define MY_MAX(a,b) ((a > b) ? a : b)
+
+#define NETPERF_LINE_MAX(x) \
+ MY_MAX(MY_MAX(MY_MAX(strlen(netperf_output_source[x].line[0]),\
+ strlen(netperf_output_source[x].line[1])),\
+ strlen(netperf_output_source[x].line[2])),\
+ strlen(netperf_output_source[x].line[3]))
+
+#define NETPERF_LINE_TOT(x) \
+ strlen(netperf_output_source[x].line[0]) +\
+ strlen(netperf_output_source[x].line[1]) +\
+ strlen(netperf_output_source[x].line[2]) +\
+ strlen(netperf_output_source[x].line[3]) + 4
+
+enum netperf_output_name
+match_string_to_output_mnenomic(char *candidate) {
+
+ enum netperf_output_name name;
+ for (name = OUTPUT_NONE; name < NETPERF_OUTPUT_MAX; name++) {
+ if(!strcasecmp(candidate,netperf_output_enum_to_str(name)))
+ return name;
+ }
+ return NETPERF_OUTPUT_UNKNOWN;
+}
+
+enum netperf_output_name
+match_string_to_output(char *candidate)
+{
+ char *h1,*temp;
+ enum netperf_output_name name;
+ int k,len;
+
+ /* at some point we may need/want to worry about leading and
+ trailing spaces, but for now we will leave that onus on the
+ user. */
+
+ for (name = OUTPUT_NONE; name < NETPERF_OUTPUT_MAX; name++) {
+ /* try for a match based on the nmemonic/enum */
+ if (!strcasecmp(candidate,netperf_output_enum_to_str(name)))
+ return name;
+
+ /* try for a match on the actual header text */
+ temp = malloc(NETPERF_LINE_TOT(name));
+ h1 = temp;
+ if (h1 != NULL) {
+ for (k = 0; ((k < 4) &&
+ (NULL != netperf_output_source[name].line[k]) &&
+ (strcmp("",netperf_output_source[name].line[k]))); k++) {
+ len = sprintf(h1,
+ "%s",
+ netperf_output_source[name].line[k]);
+ *(h1 + len) = ' ';
+ /* now move to the next starting column. for csv we aren't worried
+ about alignment between the header and the value lines */
+ h1 += len + 1;
+ }
+ /* this time we want null termination please */
+ *(h1 - 1) = 0;
+ if (!strcasecmp(candidate,temp)) {
+ free(temp);
+ return name;
+ }
+ else
+ free(temp);
+ }
+ }
+ /* if we get here it means there was no match */
+ return OUTPUT_NONE;
+}
+
+
+void
+set_output_list_all() {
+
+ int i, j; /* line, column */
+ enum netperf_output_name k;
+
+ /* Line One SOCKET_TYPE to RESPONSE_SIZE */
+ i = 0;
+ j = 0;
+ for (k = SOCKET_TYPE; k <= RESPONSE_SIZE; k++) {
+ output_list[i][j++] = k;
+ desired_output_groups |= netperf_output_source[k].output_group;
+ }
+
+ /* Line Two LOCAL_CPU_UTIL to TRANSPORT_MSS */
+ i = 1;
+ j = 0;
+ for (k = LOCAL_CPU_UTIL; k <= TRANSPORT_MSS; k++) {
+ output_list[i][j++] = k;
+ desired_output_groups |= netperf_output_source[k].output_group;
+ }
+
+ /* Line Three LOCAL_SEND_THROUGHPUT throught REMOTE_CORK */
+ i = 2;
+ j = 0;
+ for (k = LOCAL_SEND_THROUGHPUT; k <= REMOTE_CORK; k++) {
+ output_list[i][j++] = k;
+ desired_output_groups |= netperf_output_source[k].output_group;
+ }
+
+ /* Line Four LOCAL_SYSNAME through COMMAND_LINE */
+ i = 3;
+ j = 0;
+ for (k = LOCAL_SYSNAME; k <= COMMAND_LINE; k++) {
+ output_list[i][j++] = k;
+ desired_output_groups |= netperf_output_source[k].output_group;
+ }
+
+}
+
+void
+parse_output_selection_file(char *selection_file) {
+ FILE *selections;
+ char name[81]; /* best be more than enough */
+ int namepos;
+ int c;
+ int j;
+ int line,column;
+
+ selections = fopen(selection_file,"r");
+ if (!selections) {
+ fprintf(where,
+ "Could not open output selection file '%s' errno %d\n",
+ selection_file,
+ errno);
+ fflush(where);
+ exit(-1);
+ }
+
+ line = 0;
+ column = 1;
+ namepos = 0;
+ name[0] = 0;
+ name[80] = 0;
+ j = 0;
+ while (((c = fgetc(selections)) != EOF) && (line < 4)) {
+ if (namepos == 80) {
+ /* too long */
+
+ fprintf(where,
+ "Output selection starting column %d on line %d is too long\n",
+ line + 1,
+ column);
+ fflush(where);
+ exit(-1);
+ }
+ if (c == ',') {
+ /* time to check for a match, but only if we won't overflow the
+ current row of the array */
+ if (j == NETPERF_OUTPUT_MAX) {
+ fprintf(where,"Too many output selectors on line %d\n",line);
+ fflush(where);
+ exit(-1);
+ }
+ name[namepos] = 0;
+ output_list[line][j++] = match_string_to_output(name);
+ namepos = 0;
+ }
+ else if (c == '\n') {
+ /* move to the next line after checking for a match */
+ name[namepos] = 0;
+ output_list[line++][j++] = match_string_to_output(name);
+ namepos = 0;
+ j = 0;
+ }
+ else if (isprint(c)) {
+ name[namepos++] = (char)c;
+ }
+ column++;
+ }
+
+ /* ok, do we need/want to do anything here? at present we will
+ silently ignore the rest of the file if we exit the loop on line
+ count */
+ if ((c == EOF) && (namepos > 0)) {
+ name[namepos] = 0;
+ output_list[line][j] = match_string_to_output(name);
+ }
+
+}
+
+void
+parse_output_selection_line(int line, char *list) {
+
+ char *token;
+ int j;
+ enum netperf_output_name name;
+
+ /* belt and suspenders */
+ if (line < 0) {
+ fprintf(where,
+ "parse_output_selection_line called with negative line number %d\n",line);
+ fflush(where);
+ exit(-1);
+ }
+
+ /* silently ignore extra lines and only warn if debug is set */
+ if (line >= NETPERF_MAX_BLOCKS) {
+ if (debug) {
+ fprintf(where,
+ "There can be no more than %d output selection lines."
+ " Ignoring output selection line %d |%s|\n",
+ NETPERF_MAX_BLOCKS,
+ line + 1,
+ list);
+ fflush(where);
+ }
+ return;
+ }
+
+
+ j=0;
+ token = strtok(list," ,");
+ while ((token) && (j < NETPERF_OUTPUT_MAX)) {
+
+ name = match_string_to_output_mnenomic(token);
+
+ if ((name == NETPERF_OUTPUT_UNKNOWN) && (debug)) {
+ fprintf(where,"Ignoring unknown output selector %d |%s| on line %d\n",
+ j + 1,
+ token,
+ line +1);
+ fflush(where);
+ }
+ else {
+ output_list[line][j] = name;
+ desired_output_groups |= netperf_output_source[name].output_group;
+ j++;
+ }
+
+ token = strtok(NULL," ,");
+ }
+ if ((token) && (debug)) {
+ fprintf(where,
+ "There can be no more than %d output selectors per line. "
+ "Ignoring remaining selectors on line %d\n",
+ NETPERF_OUTPUT_MAX,line +1);
+ fflush(where);
+ }
+}
+
+void
+parse_output_selection_direct(char *output_selection) {
+
+ char *source,*line,*remainder,*temp;
+ char *f1, *f2, *f3;
+ int i,len,done;
+
+ len = strlen(output_selection);
+
+ source = strdup(output_selection);
+ line = (char *) malloc(len+1);
+ remainder = (char *) malloc(len+1);
+
+ if ((NULL == source) ||
+ (NULL == line) ||
+ (NULL == remainder)) {
+ fprintf(where,"Unable to malloc memory for output selection parsing\n");
+ fflush(where);
+ exit(-1);
+ }
+
+ f1 = source;
+ f2 = line;
+ f3 = remainder;
+
+ i = 0;
+ done = 0;
+ do {
+ break_args_explicit_sep(source,';',line,remainder);
+ if (line[0]) {
+ parse_output_selection_line(i,line);
+ }
+ if (remainder[0]) {
+ temp = source;
+ source = remainder;
+ remainder = temp;
+ i++;
+ /*
+ if (i == NETPERF_MAX_BLOCKS) {
+ fprintf(where,
+ "Too many output blocks requested, maximum is %d\n",
+ NETPERF_MAX_BLOCKS);
+ fflush(where);
+ exit(-1);
+ }
+ */
+ continue;
+ }
+ else {
+ done = 1;
+ }
+ } while (!done);
+
+ free(f1);
+ free(f2);
+ free(f3);
+
+}
+
+/* building blocks for output selection */
+#define NETPERF_TPUT "ELAPSED_TIME,THROUGHPUT,THROUGHPUT_UNITS"
+#define NETPERF_OUTPUT_STREAM "LSS_SIZE_END,RSR_SIZE_END,LOCAL_SEND_SIZE"
+#define NETPERF_OUTPUT_MAERTS "RSS_SIZE_END,LSR_SIZE_END,REMOTE_SEND_SIZE"
+#define NETPERF_CPU "LOCAL_CPU_UTIL,LOCAL_CPU_PERCENT_USER,LOCAL_CPU_PERCENT_SYSTEM,LOCAL_CPU_PERCENT_IOWAIT,LOCAL_CPU_PERCENT_IRQ,LOCAL_CPU_PERCENT_SWINTR,LOCAL_CPU_METHOD,REMOTE_CPU_UTIL,REMOTE_CPU_PERCENT_USER,REMOTE_CPU_PERCENT_SYSTEM,REMOTE_CPU_PERCENT_IOWAIT,REMOTE_CPU_PERCENT_IRQ,REMOTE_CPU_PERCENT_SWINTR,REMOTE_CPU_METHOD,LOCAL_SD,REMOTE_SD,SD_UNITS"
+#define NETPERF_RR "LSS_SIZE_END,LSR_SIZE_END,RSR_SIZE_END,RSS_SIZE_END,REQUEST_SIZE,RESPONSE_SIZE"
+
+void
+set_output_list_by_test() {
+
+ char *stream_no_cpu = NETPERF_OUTPUT_STREAM "," NETPERF_TPUT;
+ char *stream_cpu = NETPERF_OUTPUT_STREAM "," NETPERF_TPUT "," NETPERF_CPU;
+ char *maerts_no_cpu = NETPERF_OUTPUT_MAERTS "," NETPERF_TPUT;
+ char *maerts_cpu = NETPERF_OUTPUT_MAERTS "," NETPERF_TPUT "," NETPERF_CPU;
+ char *rr_no_cpu = NETPERF_RR "," NETPERF_TPUT;
+ char *rr_cpu = NETPERF_RR "," NETPERF_TPUT "," NETPERF_CPU;
+
+ if (debug) {
+ fprintf(where,"%s setting the output list by test\n",
+ __FUNCTION__);
+ fflush(where);
+ }
+
+ if (NETPERF_XMIT_ONLY(direction)) {
+ if (!(local_cpu_usage || remote_cpu_usage))
+ parse_output_selection_direct(stream_no_cpu);
+ else
+ parse_output_selection_direct(stream_cpu);
+ }
+ else if (NETPERF_RECV_ONLY(direction)) {
+ if (!(local_cpu_usage || remote_cpu_usage))
+ parse_output_selection_direct(maerts_no_cpu);
+ else
+ parse_output_selection_direct(maerts_cpu);
+ }
+ else if (NETPERF_CC(direction)) {
+ if (!(local_cpu_usage || remote_cpu_usage))
+ parse_output_selection_direct(rr_no_cpu);
+ else
+ parse_output_selection_direct(rr_cpu);
+ }
+ else if (NETPERF_IS_RR(direction)) {
+ if (!(local_cpu_usage || remote_cpu_usage))
+ parse_output_selection_direct(rr_no_cpu);
+ else
+ parse_output_selection_direct(rr_cpu);
+ }
+ else {
+ /* no idea */
+ if (debug) {
+ fprintf(where,"Cannot determine default test output, using mins\n");
+ fflush(where);
+ }
+ parse_output_selection_direct(NETPERF_TPUT "," NETPERF_CPU);
+ }
+}
+
+void
+parse_output_selection(char *output_selection) {
+
+ if (debug) {
+ fprintf(where,"%s is parsing the output selection '%s'\n",
+ __FUNCTION__,
+ output_selection);
+ fflush(where);
+ }
+
+ /* is it the magic keyword? */
+ if (strcasecmp(output_selection,"all") == 0) {
+ set_output_list_all();
+ }
+ /* do not forget the case when the output_selection is a single
+ mnemonic without any separators... */
+ else if (strchr(output_selection,',') ||
+ strchr(output_selection,';') ||
+ (match_string_to_output_mnenomic(output_selection) !=
+ NETPERF_OUTPUT_UNKNOWN)) {
+ parse_output_selection_direct(output_selection);
+ }
+ else {
+ parse_output_selection_file(output_selection);
+ }
+ if (debug > 2) {
+ dump_netperf_output_list(stderr);
+ }
+ return;
+}
+
+static void
+set_output_elt(enum netperf_output_name name,
+ char *line0, char *line1, char *line2, char *line3,
+ char *format,
+ void *value,
+ unsigned int out_default,
+ unsigned int group,
+ enum netperf_output_type type) {
+
+ netperf_output_source[name].output_name = name;
+ netperf_output_source[name].line[0] = line0;
+ netperf_output_source[name].line[1] = line1;
+ netperf_output_source[name].line[2] = line2;
+ netperf_output_source[name].line[3] = line3;
+ netperf_output_source[name].format = format;
+ netperf_output_source[name].display_value = value;
+ netperf_output_source[name].output_default = out_default;
+ netperf_output_source[name].output_group = group;
+ netperf_output_source[name].max_line_len = NETPERF_LINE_MAX(name);
+ netperf_output_source[name].tot_line_len = NETPERF_LINE_TOT(name);
+ netperf_output_source[name].output_type = type;
+}
+
+void
+print_omni_init_list() {
+
+ int i;
+
+ if (debug) {
+ fprintf(where,"%s called\n",
+ __FUNCTION__);
+ }
+
+ /* belts and suspenders everyone... */
+ for (i = NETPERF_OUTPUT_UNKNOWN; i < NETPERF_OUTPUT_MAX; i++) {
+ netperf_output_source[i].output_name = i;
+ netperf_output_source[i].max_line_len = 0;
+ netperf_output_source[i].tot_line_len = 0;
+ netperf_output_source[i].line[0] = "";
+ netperf_output_source[i].line[1] = "";
+ netperf_output_source[i].line[2] = "";
+ netperf_output_source[i].line[3] = "";
+ netperf_output_source[i].format = "";
+ netperf_output_source[i].display_value = NULL;
+ netperf_output_source[i].output_default = 1;
+ netperf_output_source[i].output_group = 0;
+ netperf_output_source[i].output_type = NETPERF_TYPE_UNKNOWN;
+ }
+
+ set_output_elt(OUTPUT_NONE, " ", "", "", "", "%s", &" ",1, 0,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(COMMAND_LINE, "Command","Line","","","\"%s\"",
+ command_line,1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(UUID, "Test", "UUID", "", "", "%s", test_uuid, 1, 0,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(RESULT_BRAND, "Result", "Tag", "", "", "\"%s\"",
+ result_brand, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(SOCKET_TYPE, "Socket", "Type", "", "", "%s",
+ socket_type_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(DIRECTION, "Direction", "", "", "", "%s",
+ direction_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(PROTOCOL, "Protocol", "", "", "", "%s",
+ protocol_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(ELAPSED_TIME, "Elapsed", "Time", "(sec)", "", "%.2f",
+ &elapsed_time_double, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(SOURCE_PORT, "Source", "Port", "", "", "%s",
+ local_data_port, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(SOURCE_ADDR, "Source", "Address", "", "", "%s",
+ local_data_address, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(SOURCE_FAMILY, "Source", "Family", "", "", "%d",
+ &local_data_family, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(DEST_PORT, "Destination", "Port", "", "", "%s",
+ remote_data_port, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(DEST_ADDR, "Destination", "Address", "", "", "%s",
+ remote_data_address, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(DEST_FAMILY, "Destination", "Family", "", "", "%d",
+ &remote_data_family, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(THROUGHPUT, "Throughput", "", "", "", "%.2f",
+ &thruput, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_SEND_THROUGHPUT, "Local", "Send", "Throughput", "",
+ "%.2f", &local_send_thruput, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_RECV_THROUGHPUT, "Local", "Recv", "Throughput", "",
+ "%.2f", &local_recv_thruput, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_SEND_THROUGHPUT, "Remote", "Send", "Throughput", "",
+ "%.2f", &remote_send_thruput, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_RECV_THROUGHPUT, "Remote", "Recv", "Throughput", "",
+ "%.2f", &remote_recv_thruput, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(THROUGHPUT_UNITS, "Throughput", "Units", "", "", "%s/s",
+ thruput_format_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(CONFIDENCE_LEVEL, "Confidence", "Level", "Percent", "", "%d",
+ &confidence_level, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(CONFIDENCE_INTERVAL, "Confidence", "Width", "Target", "",
+ "%f", &interval_pct, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(CONFIDENCE_ITERATION, "Confidence", "Iterations", "Run", "",
+ "%d", &confidence_iteration, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(THROUGHPUT_CONFID, "Throughput", "Confidence", "Width (%)",
+ "", "%.3f", &result_confid_pct, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_CPU_CONFID, "Local", "CPU", "Confidence", "Width (%)",
+ "%.3f", &loc_cpu_confid_pct, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_CPU_CONFID, "Remote", "CPU", "Confidence", "Width (%)",
+ "%.3f", &rem_cpu_confid_pct, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(RT_LATENCY, "Round", "Trip", "Latency", "usec/tran", "%.3f",
+ &rtt_latency, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(TRANSACTION_RATE, "Transaction", "Rate", "Tran/s", "", "%.3f",
+ &transaction_rate, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(TRANSPORT_MSS, "Transport", "MSS", "bytes", "", "%d",
+ &transport_mss, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_TRANSPORT_RETRANS, "Local", "Transport",
+ "Retransmissions", "", "%d", &local_transport_retrans, 1, 0,
+ NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_TRANSPORT_RETRANS, "Remote", "Transport",
+ "Retransmissions", "", "%d", &remote_transport_retrans, 1, 0,
+ NETPERF_TYPE_INT32);
+
+ set_output_elt(REQUEST_SIZE, "Request", "Size", "Bytes", "", "%d",
+ &req_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RESPONSE_SIZE, "Response", "Size", "Bytes", "", "%d",
+ &rsp_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(BURST_SIZE, "Initial", "Burst", "Requests", "", "%d",
+ &first_burst_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSS_SIZE_REQ, "Local", "Send Socket", "Size", "Requested",
+ "%d", &lss_size_req, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSS_SIZE, "Local", "Send Socket", "Size", "Initial", "%d",
+ &lss_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSS_SIZE_END, "Local", "Send Socket", "Size", "Final", "%d",
+ &lss_size_end, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSR_SIZE_REQ, "Local", "Recv Socket", "Size", "Requested",
+ "%d", &lsr_size_req, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSR_SIZE, "Local", "Recv Socket", "Size", "Initial", "%d",
+ &lsr_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LSR_SIZE_END, "Local", "Recv Socket", "Size", "Final", "%d",
+ &lsr_size_end, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SEND_SIZE, "Local", "Send", "Size", "", "%d",
+ &send_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_SIZE, "Local", "Recv", "Size", "", "%d",
+ &recv_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SEND_CALLS, "Local", "Send", "Calls", "", "%"PRIu64,
+ &local_send_calls, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(LOCAL_RECV_CALLS, "Local", "Recv", "Calls", "", "%"PRIu64,
+ &local_receive_calls, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(LOCAL_BYTES_PER_RECV, "Local", "Bytes", "Per", "Recv", "%.2f",
+ &bytes_per_recv, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_BYTES_PER_SEND, "Local", "Bytes", "Per", "Send", "%.2f",
+ &bytes_per_send, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_BYTES_RECVD, "Local", "Bytes", "Received", "", "%"PRIu64,
+ &bytes_received, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(LOCAL_BYTES_SENT, "Local", "Bytes", "Sent", "", "%"PRIu64,
+ &bytes_sent, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(LOCAL_BYTES_XFERD, "Local", "Bytes", "Xferred", "", "%.0f",
+ &bytes_xferd, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_SEND_WIDTH, "Local", "Send", "Width", "", "%d",
+ &send_width, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_WIDTH, "Local", "Recv", "Width", "", "%d",
+ &recv_width, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SEND_OFFSET, "Local", "Send", "Offset", "", "%d",
+ &local_send_offset, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_OFFSET, "Local", "Recv", "Offset", "", "%d",
+ &local_recv_offset, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_ALIGN, "Local", "Recv", "Alignment", "", "%d",
+ &local_recv_align, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SEND_ALIGN, "Local", "Send", "Alignment", "", "%d",
+ &local_send_align, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SEND_DIRTY_COUNT, "Local", "Send", "Dirty", "Count",
+ "%d", &loc_dirty_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_DIRTY_COUNT, "Local", "Recv", "Dirty", "Count",
+ "%d", &loc_dirty_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_RECV_CLEAN_COUNT, "Local", "Recv", "Clean", "Count",
+ "%d", &loc_clean_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_CPU_UTIL, "Local", "CPU", "Util", "%", "%.2f",
+ &local_cpu_utilization, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PERCENT_USER, "Local", "CPU", "User", "%", "%.2f",
+ &lib_local_cpu_stats.cpu_user, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PERCENT_SYSTEM,
+ "Local", "CPU", "System", "%", "%.2f",
+ &lib_local_cpu_stats.cpu_system, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PERCENT_IOWAIT,
+ "Local", "CPU", "I/O", "%", "%.2f",
+ &lib_local_cpu_stats.cpu_iowait, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PERCENT_IRQ,
+ "Local", "CPU", "IRQ", "%", "%.2f",
+ &lib_local_cpu_stats.cpu_irq, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PERCENT_SWINTR,
+ "Local", "CPU", "swintr", "%", "%.2f",
+ &lib_local_cpu_stats.cpu_swintr, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PEAK_UTIL, "Local", "Peak", "Per CPU", "Util %",
+ "%.2f", &lib_local_cpu_stats.peak_cpu_util, 1, 0,
+ NETPERF_TYPE_FLOAT);
+
+ set_output_elt(LOCAL_CPU_PEAK_ID, "Local", "Peak", "Per CPU", "ID", "%d",
+ &lib_local_cpu_stats.peak_cpu_id, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_CPU_BIND, "Local", "CPU", "Bind", "", "%d",
+ &local_proc_affinity, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SD, "Local", "Service", "Demand", "", "%.3f",
+ &local_service_demand_double, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(SD_UNITS, "Service", "Demand", "Units", "", "%s",
+ sd_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_CPU_METHOD, "Local", "CPU", "Util", "Method", "%c",
+ &local_cpu_method, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_CPU_COUNT, "Local", "CPU", "Count", "", "%d",
+ &lib_num_loc_cpus, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_NODELAY, "Local", "NODELAY", "", "", "%d",
+ &loc_nodelay, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_CORK, "Local", "Cork", "", "", "%d",
+ &loc_tcpcork, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSS_SIZE_REQ, "Remote", "Send Socket", "Size", "Requested",
+ "%d", &rss_size_req, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSS_SIZE, "Remote", "Send Socket", "Size", "Initial", "%d",
+ &rss_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSS_SIZE_END, "Remote", "Send Socket", "Size", "Final", "%d",
+ &rss_size_end, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSR_SIZE_REQ, "Remote", "Recv Socket", "Size", "Requested",
+ "%d", &rsr_size_req, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSR_SIZE, "Remote", "Recv Socket", "Size", "Initial", "%d",
+ &rsr_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(RSR_SIZE_END, "Remote", "Recv Socket", "Size", "Final", "%d",
+ &rsr_size_end, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SEND_SIZE, "Remote", "Send", "Size", "", "%d",
+ &remote_send_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_SIZE, "Remote", "Recv", "Size", "", "%d",
+ &remote_recv_size, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SEND_CALLS, "Remote", "Send", "Calls", "", "%"PRIu64,
+ &remote_send_calls, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(REMOTE_RECV_CALLS, "Remote", "Recv", "Calls", "", "%"PRIu64,
+ &remote_receive_calls, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(REMOTE_BYTES_PER_RECV, "Remote", "Bytes", "Per", "Recv",
+ "%.2f", &remote_bytes_per_recv, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_BYTES_PER_SEND, "Remote", "Bytes", "Per", "Send",
+ "%.2f", &remote_bytes_per_send, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_BYTES_RECVD, "Remote", "Bytes", "Received", "",
+ "%"PRIu64, &remote_bytes_received, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(REMOTE_BYTES_SENT, "Remote", "Bytes", "Sent", "", "%"PRIu64,
+ &remote_bytes_sent, 1, 0, NETPERF_TYPE_UINT64);
+
+ set_output_elt(REMOTE_BYTES_XFERD, "Remote", "Bytes", "Xferred", "", "%.0f",
+ &remote_bytes_xferd, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_SEND_WIDTH, "Remote", "Send", "Width", "", "%d",
+ &remote_send_width, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_WIDTH, "Remote", "Recv", "Width", "", "%d",
+ &remote_recv_width, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SEND_OFFSET, "Remote", "Send", "Offset", "", "%d",
+ &remote_send_offset, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_OFFSET, "Remote", "Recv", "Offset", "", "%d",
+ &remote_recv_offset, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_ALIGN, "Remote", "Recv", "Alignment", "", "%d",
+ &remote_recv_align, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SEND_ALIGN, "Remote", "Send", "Alignment", "", "%d",
+ &remote_send_align, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SEND_DIRTY_COUNT, "Remote", "Send", "Dirty", "Count",
+ "%d", &rem_dirty_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_DIRTY_COUNT, "Remote", "Recv", "Dirty", "Count",
+ "%d", &rem_dirty_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_RECV_CLEAN_COUNT, "Remote", "Recv", "Clean", "Count",
+ "%d", &rem_clean_count, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_CPU_UTIL, "Remote", "CPU", "Util", "%", "%.2f",
+ &remote_cpu_utilization, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PERCENT_USER, "Remote", "CPU", "User", "%", "%.2f",
+ &lib_remote_cpu_stats.cpu_user, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PERCENT_SYSTEM,
+ "Remote", "CPU", "System", "%", "%.2f",
+ &lib_remote_cpu_stats.cpu_system, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PERCENT_IOWAIT,
+ "Remote", "CPU", "I/O", "%", "%.2f",
+ &lib_remote_cpu_stats.cpu_iowait, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PERCENT_IRQ,
+ "Remote", "CPU", "IRQ", "%", "%.2f",
+ &lib_remote_cpu_stats.cpu_irq, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PERCENT_SWINTR,
+ "Remote", "CPU", "swintr", "%", "%.2f",
+ &lib_remote_cpu_stats.cpu_swintr, 1, 0, NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PEAK_UTIL, "Remote", "Peak", "Per CPU", "Util %",
+ "%.2f", &lib_remote_cpu_stats.peak_cpu_util, 1, 0,
+ NETPERF_TYPE_FLOAT);
+
+ set_output_elt(REMOTE_CPU_PEAK_ID, "Remote", "Peak", "Per CPU", "ID", "%d",
+ &lib_remote_cpu_stats.peak_cpu_id, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_CPU_BIND, "Remote", "CPU", "Bind", "", "%d",
+ &remote_proc_affinity, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SD, "Remote", "Service", "Demand", "", "%.3f",
+ &remote_service_demand_double, 1, 0, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(REMOTE_CPU_METHOD, "Remote", "CPU", "Util", "Method", "%c",
+ &remote_cpu_method, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_CPU_COUNT, "Remote", "CPU", "Count", "", "%d",
+ &lib_num_rem_cpus, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_NODELAY, "Remote", "NODELAY", "", "", "%d",
+ &rem_nodelay, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_CORK, "Remote", "Cork", "", "", "%d",
+ &rem_tcpcork, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_DRIVER_NAME, "Local", "Driver", "Name", "", "%s",
+ deprecated_str, 1, OMNI_WANT_LOC_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_DRIVER_VERSION, "Local", "Driver", "Version", "", "%s",
+ deprecated_str, 1, OMNI_WANT_LOC_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_DRIVER_FIRMWARE, "Local", "Driver", "Firmware", "",
+ "%s", deprecated_str, 1, OMNI_WANT_LOC_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_DRIVER_BUS, "Local", "Driver", "Bus", "", "%s",
+ deprecated_str, 1, OMNI_WANT_LOC_DRVINFO, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_DRIVER_NAME, "Remote", "Driver", "Name", "", "%s",
+ deprecated_str, 1, OMNI_WANT_REM_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_DRIVER_VERSION, "Remote", "Driver", "Version", "",
+ "%s", deprecated_str, 1, OMNI_WANT_REM_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_DRIVER_FIRMWARE, "Remote", "Driver", "Firmware", "",
+ "%s", deprecated_str, 1, OMNI_WANT_REM_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_DRIVER_BUS, "Remote", "Driver", "Bus", "", "%s",
+ deprecated_str, 1, OMNI_WANT_REM_DRVINFO,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_INTERFACE_SUBDEVICE, "Local", "Interface", "Subdevice",
+ "", "0x%.4x", &local_interface_subdevice, 1,
+ OMNI_WANT_LOC_IFIDS, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_INTERFACE_DEVICE, "Local", "Interface", "Device", "",
+ "0x%.4x", &local_interface_device, 1, OMNI_WANT_LOC_IFIDS,
+ NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_INTERFACE_SUBVENDOR, "Local", "Interface", "Subvendor",
+ "", "0x%.4x", &local_interface_subvendor, 1,
+ OMNI_WANT_LOC_IFIDS, NETPERF_TYPE_UINT32);
+
+ set_output_elt(LOCAL_INTERFACE_VENDOR, "Local", "Interface", "Vendor", "",
+ "0x%.4x", &local_interface_vendor, 1, OMNI_WANT_LOC_IFIDS,
+ NETPERF_TYPE_UINT32);
+
+ set_output_elt(REMOTE_INTERFACE_SUBDEVICE, "Remote", "Interface",
+ "Subdevice", "", "0x%.4x", &remote_interface_subdevice, 1,
+ OMNI_WANT_REM_IFIDS, NETPERF_TYPE_UINT32);
+
+ set_output_elt(REMOTE_INTERFACE_DEVICE, "Remote", "Interface", "Device", "",
+ "0x%.4x", &remote_interface_device, 1, OMNI_WANT_REM_IFIDS,
+ NETPERF_TYPE_UINT32);
+
+ set_output_elt(REMOTE_INTERFACE_SUBVENDOR, "Remote", "Interface",
+ "Subvendor", "", "0x%.4x", &remote_interface_subvendor, 1,
+ OMNI_WANT_REM_IFIDS, NETPERF_TYPE_UINT32);
+
+ set_output_elt(REMOTE_INTERFACE_VENDOR, "Remote", "Interface", "Vendor", "",
+ "0x%.4x", &remote_interface_vendor, 1, OMNI_WANT_REM_IFIDS,
+ NETPERF_TYPE_UINT32);
+
+ set_output_elt(LOCAL_INTERFACE_NAME, "Local", "Interface", "Name", "", "%s",
+ deprecated_str, 1, OMNI_WANT_LOC_IFNAME,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_INTERFACE_NAME, "Remote", "Interface", "Name", "",
+ "%s", deprecated_str, 1, OMNI_WANT_REM_IFNAME,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_INTERFACE_SLOT, "Local", "Interface", "Slot", "", "%s",
+ deprecated_str, 1, OMNI_WANT_LOC_IFSLOT,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_INTERFACE_SLOT, "Remote", "Interface", "Slot", "",
+ "%s", deprecated_str, 1, OMNI_WANT_REM_IFSLOT,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_MACHINE, "Remote", "Machine", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_VERSION, "Remote", "Version", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_RELEASE, "Remote", "Release", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_SYSNAME, "Remote", "Sysname", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_MACHINE, "Local", "Machine", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_VERSION, "Local", "Version", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_RELEASE, "Local", "Release", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_SYSNAME, "Local", "Sysname", "", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_INTERVAL_USECS, "Remote", "Interval", "Usecs", "",
+ "%d", &remote_interval_usecs, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_INTERVAL_BURST, "Remote", "Interval", "Burst", "",
+ "%d", &remote_interval_burst, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SECURITY_ENABLED, "Local", "OS", "Security", "Enabled",
+ "%s", deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_SECURITY_TYPE, "Local", "OS", "Security", "Type", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_SECURITY_SPECIFIC, "Local", "OS", "Security",
+ "Specific", "%s", deprecated_str, 1, 0,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_SECURITY_ENABLED_NUM, "Local", "OS", "Security",
+ "Enabled Num", "%d", &local_security_enabled_num, 1, 0,
+ NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SECURITY_TYPE_ID, "Local", "OS", "Security", "Type ID",
+ "%d", &local_security_type_id, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SECURITY_ENABLED, "Remote", "OS", "Security",
+ "Enabled", "%s", deprecated_str, 1, 0,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_SECURITY_TYPE, "Remote", "OS", "Security", "Type",
+ "%s", deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_SECURITY_SPECIFIC, "Remote", "OS", "Security",
+ "Specific", "%s", deprecated_str, 1, 0,
+ NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_SECURITY_ENABLED_NUM, "Remote", "OS", "Security",
+ "Enabled", "%d", &remote_security_enabled_num, 1, 0,
+ NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SECURITY_TYPE_ID, "Remote", "OS", "Security", "Type",
+ "%d", &remote_security_type_id, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_INTERVAL_USECS, "Local", "Interval", "Usecs", "", "%d",
+ &interval_usecs, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_INTERVAL_BURST, "Local", "Interval", "Burst", "", "%d",
+ &interval_burst, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SYSTEM_MODEL, "Remote", "System", "Model", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_CPU_MODEL, "Remote", "CPU", "Model", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_CPU_FREQUENCY, "Remote", "CPU", "Frequency", "MHz",
+ "%d", &remote_cpu_frequency, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SYSTEM_MODEL, "Local", "System", "Model", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_CPU_MODEL, "Local", "CPU", "Model", "", "%s",
+ deprecated_str, 1, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_CPU_FREQUENCY, "Local", "CPU", "Frequency", "MHz", "%d",
+ &local_cpu_frequency, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(MIN_LATENCY, "Minimum", "Latency", "Microseconds", "", "%d",
+ &min_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_INT32);
+
+ set_output_elt(MAX_LATENCY, "Maximum", "Latency", "Microseconds", "", "%d",
+ &max_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_INT32);
+
+ set_output_elt(P50_LATENCY, "50th", "Percentile", "Latency", "Microseconds",
+ "%d", &p50_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_INT32);
+
+ set_output_elt(P90_LATENCY, "90th", "Percentile", "Latency", "Microseconds",
+ "%d", &p90_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_INT32);
+
+ set_output_elt(P99_LATENCY, "99th", "Percentile", "Latency", "Microseconds",
+ "%d", &p99_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_INT32);
+
+ set_output_elt(MEAN_LATENCY, "Mean", "Latency", "Microseconds", "", "%.2f",
+ &mean_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(STDDEV_LATENCY, "Stddev", "Latency", "Microseconds", "",
+ "%.2f", &stddev_latency, 0, OMNI_WANT_STATS, NETPERF_TYPE_DOUBLE);
+
+ set_output_elt(LOCAL_SOCKET_PRIO, "Local", "Socket", "Priority", "", "%d",
+ &local_socket_prio, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SOCKET_PRIO, "Remote", "Socket", "Priority", "", "%d"
+ , &remote_socket_prio, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_SOCKET_TOS, "Local", "Socket", "TOS", "", "0x%.2x",
+ &local_socket_tos, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(REMOTE_SOCKET_TOS, "Remote", "Socket", "TOS", "", "0x%.2x",
+ &remote_socket_tos, 1, 0, NETPERF_TYPE_INT32);
+
+ set_output_elt(LOCAL_CONG_CONTROL, "Local", "Congestion", "Control",
+ "Algorithm", "%s", local_cong_control, 0,
+ OMNI_WANT_LOC_CONG, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_CONG_CONTROL, "Remote", "Congestion", "Control",
+ "Algorithm", "%s", remote_cong_control, 0,
+ OMNI_WANT_REM_CONG, NETPERF_TYPE_CHAR);
+
+ set_output_elt(LOCAL_FILL_FILE, "Local", "Fill", "File", "", "%s",
+ local_fill_file, 0, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(REMOTE_FILL_FILE, "Remote", "Fill", "File", "", "%s",
+ remote_fill_file, 0, 0, NETPERF_TYPE_CHAR);
+
+ set_output_elt(OUTPUT_END, "This", "Is", "The", "End", "%s",
+ NULL, 0, 0, NETPERF_TYPE_CHAR);
+
+}
+
+void
+print_omni_init() {
+
+ int i,j;
+
+ if (debug) {
+ fprintf(where,"%s entered\n",
+ __FUNCTION__);
+ fflush(where);
+ }
+
+ /* why is this before the if you ask? because some of the output
+ specifiers are char * rather than char[] and when I wanted to
+ start setting output_group flags I was needing to call
+ print_omni_init() before the char * 's were malloced, which meant
+ the netperf_output_source got NULL pointers. there is
+ undoubtedly a cleaner way to do all this. raj 20110629 */
+
+ print_omni_init_list();
+
+ if (printing_initialized) return;
+
+ printing_initialized = 1;
+
+
+ /* belts and suspenders */
+ for (j = 0; j < NETPERF_MAX_BLOCKS; j++)
+ for (i = 0; i < NETPERF_OUTPUT_MAX; i++)
+ output_list[j][i] = OUTPUT_END;
+
+
+ if (output_selection_spec) {
+ parse_output_selection(output_selection_spec);
+ }
+ else {
+ set_output_list_by_test();
+ }
+
+}
+
+/* why? because one cannot simply pass a pointer to snprintf - well
+ except when it is expecting one... */
+int
+my_snprintf(char *buffer, size_t size, netperf_output_elt_t *output_elt)
+{
+ switch (output_elt->output_type) {
+ case NETPERF_TYPE_CHAR:
+ return snprintf(buffer, size,
+ output_elt->format,
+ (char *)output_elt->display_value);
+ break;
+ case NETPERF_TYPE_INT32:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(int *)(output_elt->display_value));
+ break;
+ case NETPERF_TYPE_UINT32:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(unsigned int *)(output_elt->display_value));
+ break;
+ case NETPERF_TYPE_INT64:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(long long *)(output_elt->display_value));
+ break;
+ case NETPERF_TYPE_UINT64:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(unsigned long long *)(output_elt->display_value));
+ break;
+ case NETPERF_TYPE_FLOAT:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(float *)(output_elt->display_value));
+ break;
+ case NETPERF_TYPE_DOUBLE:
+ return snprintf(buffer, size,
+ output_elt->format,
+ *(double *)(output_elt->display_value));
+ break;
+ default:
+ fprintf(stderr,
+ "Unknown/unsupported output_elt output_type of %d\n",
+ output_elt->output_type);
+ fflush(stderr);
+ exit(-1);
+ }
+}
+
+void
+print_omni_csv()
+{
+
+ int i,j,k,buflen,vallen;
+
+ char *hdr1 = NULL;
+ char *val1 = NULL;
+ char *h1 = NULL;
+ char *v1 = NULL;
+ char tmpval[1024];
+
+ buflen = 0;
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ for (j = 0;
+ ((j < NETPERF_OUTPUT_MAX) &&
+ (output_list[i][j] != OUTPUT_END));
+ j++) {
+ if ((netperf_output_source[output_list[i][j]].format != NULL) &&
+ (netperf_output_source[output_list[i][j]].display_value != NULL)) {
+ vallen =
+ my_snprintf(tmpval,
+ 1024,
+ &(netperf_output_source[output_list[i][j]]));
+ if (vallen == -1) {
+ fprintf(where,"my_snprintf failed on %s with format %s\n",
+ netperf_output_enum_to_str(j),
+ netperf_output_source[output_list[i][j]].format);
+ fflush(where);
+ }
+ vallen += 1; /* forget not the terminator */
+ }
+ else
+ vallen = 0;
+
+ if (vallen >
+ netperf_output_source[output_list[i][j]].tot_line_len)
+ netperf_output_source[output_list[i][j]].tot_line_len = vallen;
+
+ buflen +=
+ netperf_output_source[output_list[i][j]].tot_line_len;
+ }
+ }
+
+ if (print_headers) hdr1 = malloc(buflen + 1);
+ val1 = malloc(buflen + 1);
+
+ if (((hdr1 == NULL) && (print_headers)) ||
+ (val1 == NULL)) {
+ fprintf(where,"unable to allocate output buffers\n");
+ fflush(where);
+ exit(-1);
+ }
+
+ if (print_headers) memset(hdr1,' ',buflen + 1);
+ memset(val1,' ',buflen + 1);
+
+ /* ostensibly, we now "know" that we have enough space in all our
+ strings, and we have spaces where we want them etc */
+ h1 = hdr1;
+ v1 = val1;
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ for (j = 0;
+ ((j < NETPERF_OUTPUT_MAX) &&
+ (output_list[i][j] != OUTPUT_END));
+ j++) {
+ int len;
+ len = 0;
+ if (print_headers) {
+ for (k = 0; ((k < 4) &&
+ (NULL !=
+ netperf_output_source[output_list[i][j]].line[k]) &&
+ (strcmp("",netperf_output_source[output_list[i][j]].line[k]))); k++) {
+
+ len = sprintf(h1,
+ "%s",
+ netperf_output_source[output_list[i][j]].line[k]);
+ *(h1 + len) = ' ';
+ /* now move to the next starting column. for csv we aren't worried
+ about alignment between the header and the value lines */
+ h1 += len + 1;
+ }
+ *(h1 - 1) = ',';
+ }
+ if ((netperf_output_source[output_list[i][j]].format != NULL) &&
+ (netperf_output_source[output_list[i][j]].display_value != NULL)) {
+ /* tot_line_len is bogus here, but should be "OK" ? */
+ len = my_snprintf(v1,
+ netperf_output_source[output_list[i][j]].tot_line_len,
+ &(netperf_output_source[output_list[i][j]]));
+
+ /* nuke the trailing \n" from the string routine. */
+ *(v1 + len) = ',';
+ v1 += len + 1;
+ }
+ else {
+ /* we need a ',' even if there is no value */
+ *v1 = ',';
+ v1 += 2;
+ }
+ }
+ }
+
+ /* ok, _now_ null terminate each line by nuking the last comma. do
+ we have an OBOB here? */
+ if (print_headers) *(h1-1) = 0;
+ *(v1-1) = 0;
+ /* and now spit it out, but only if it is going to have something
+ in it. we don't want a bunch of blank lines or nulls... */
+ if (output_list[0][0] != OUTPUT_END) {
+ if (print_headers) printf("%s\n",hdr1);
+ printf("%s\n",val1);
+ }
+
+ if (hdr1 != NULL) free(hdr1);
+ if (val1 != NULL) free(val1);
+
+}
+
+void
+print_omni_keyword()
+{
+ /* this one should be the simplest of all - no buffers to allocate,
+ just spit it all out. raj 20080805 */
+
+ int i,j;
+ char tmpval[1024];
+ int vallen;
+
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ for (j = 0;
+ ((j < NETPERF_OUTPUT_MAX) &&
+ (output_list[i][j] != OUTPUT_END));
+ j++) {
+ if ((netperf_output_source[output_list[i][j]].format != NULL) &&
+ (netperf_output_source[output_list[i][j]].display_value != NULL)) {
+ vallen =
+ my_snprintf(tmpval,
+ 1024,
+ &(netperf_output_source[output_list[i][j]]));
+ if (vallen == -1) {
+ snprintf(tmpval,
+ 1024,
+ "my_snprintf failed with format %s\n",
+ netperf_output_source[output_list[i][j]].format);
+ }
+ fprintf(where,
+ "%s=%s\n",netperf_output_enum_to_str(output_list[i][j]),
+ tmpval);
+ }
+ }
+ }
+ fflush(where);
+}
+
+void
+print_omni_human()
+{
+
+ int i,j,k,buflen,buflen_max;
+
+ char *hdr[4];
+ char *val1 = NULL;
+ char tmpval[1024]; /* excessive, but we may have the command line */
+ int vallen;
+
+ for (k = 0; k < 4; k ++) {
+ hdr[k] = NULL;
+ }
+
+ /* decisions, decisions... walk the list twice to only need to
+ allocate the charcter buffers once, or walk it once and possibly
+ reallocate them as I go... oh, lets walk it twice just for fun to
+ start. since only now do we know that the values are around to be
+ printed, we should try the snprintf for the value and see how
+ much space it wants and update max_line_len accordingly */
+ buflen_max = 0;
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ buflen = 0;
+ for (j = 0;
+ ((j < NETPERF_OUTPUT_MAX) &&
+ (output_list[i][j] != OUTPUT_END));
+ j++) {
+ if ((netperf_output_source[output_list[i][j]].format != NULL) &&
+ (netperf_output_source[output_list[i][j]].display_value !=
+ NULL))
+ /* need to count the \n */
+ vallen = my_snprintf(tmpval,
+ 1024,
+ &(netperf_output_source[output_list[i][j]])) + 1;
+ else
+ vallen = 0;
+
+ if (vallen >
+ netperf_output_source[output_list[i][j]].max_line_len)
+ netperf_output_source[output_list[i][j]].max_line_len = vallen;
+
+ buflen +=
+ netperf_output_source[output_list[i][j]].max_line_len + 1;
+ }
+
+ if (buflen > buflen_max)
+ buflen_max = buflen;
+ }
+
+ /* more belts and suspenders */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ hdr[k] = malloc(buflen_max+1);
+ }
+ val1 = malloc(buflen_max+1);
+
+ /* we could probably be more succinct here but perhaps the compiler
+ can figure that out for us :) */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ if (hdr[k] == NULL) {
+ fprintf(where,"Unable to allocate output buffers\n");
+ fflush(where);
+ exit(-1);
+ }
+ }
+
+ /* ostensibly, we now "know" that we have enough space in all our
+ strings, and we have spaces where we want them etc */
+ for (i = 0; i < NETPERF_MAX_BLOCKS; i++) {
+ char *h[4];
+ char *v1 = val1;
+
+ for (k = 0; k < 4; k++) h[k] = hdr[k];
+
+ /* we want to blank things out each time since we skip around a lot */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ memset(hdr[k],' ',buflen_max+1);
+ }
+ memset(val1,' ',buflen_max+1);
+
+
+ for (j = 0;
+ ((j < NETPERF_OUTPUT_MAX) &&
+ (output_list[i][j] != OUTPUT_END));
+ j++) {
+ if (print_headers) {
+ for (k = 0; k < 4; k++) {
+ memcpy(h[k],
+ netperf_output_source[output_list[i][j]].line[k],
+ strlen(netperf_output_source[output_list[i][j]].line[k]));
+ }
+ }
+ if ((netperf_output_source[output_list[i][j]].format != NULL) &&
+ (netperf_output_source[output_list[i][j]].display_value != NULL)) {
+ int len;
+ len = my_snprintf(v1,
+ netperf_output_source[output_list[i][j]].max_line_len,
+ &(netperf_output_source[output_list[i][j]]));
+ /* nuke the trailing \n" from the string routine. */
+ *(v1 + len) = ' ';
+ }
+ /* now move to the next starting column */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ h[k] +=
+ netperf_output_source[output_list[i][j]].max_line_len + 1;
+ }
+ v1 += netperf_output_source[output_list[i][j]].max_line_len + 1;
+ }
+ /* ok, _now_ null terminate each line. do we have an OBOB here? */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ *h[k] = 0;
+ }
+ *v1 = 0;
+ /* and now spit it out, but only if it is going to have something
+ in it. we don't want a bunch of blank lines or nulls... at some
+ point we might want to work backwards collapsine whitespace from
+ the right but for now, we won't bother */
+ if (output_list[i][0] != OUTPUT_END) {
+ if (i > 0) printf("\n"); /* we want a blank line between blocks ? */
+ for (k = 0; (k < 4) && (print_headers); k++) {
+ printf("%s\n",hdr[k]);
+ }
+ printf("%s\n",val1);
+ }
+ };
+ for (k = 0; k < 4; k++) {
+ if (hdr[k] != NULL) free(hdr[k]);
+ }
+}
+
+void
+print_omni()
+{
+
+ print_omni_init();
+
+ if (debug > 2)
+ dump_netperf_output_source(where);
+
+ switch (netperf_output_mode) {
+ case CSV:
+ print_omni_csv();
+ break;
+ case KEYVAL:
+ print_omni_keyword();
+ break;
+ case HUMAN:
+ print_omni_human();
+ break;
+ default:
+ fprintf(where,"Yo Rick! There is a bug in netperf_output_mode!\n");
+ fflush(where);
+ exit(-1);
+ }
+
+}
+/* for the next few routines (connect, accept, send, recv,
+ disconnect/close) we will use a return of -1 to mean times up, -2
+ to mean a transient error (eg ENOBUFS on a UDP send call) and -3 to
+ mean hard error. this means it is ok for the connect routine to
+ return a 0 (zero) if that happens to be the fd/SOCKET we get and in
+ theory we will be able to support zero-length messages on those
+ protocols which support it. all in theory of course. raj
+ 2008-01-09 */
+
+int
+connect_data_socket(SOCKET send_socket, struct addrinfo *remote_res, int dont_give_up)
+{
+ int ret;
+
+ /* Connect up to the remote port on the data socket */
+ if ((ret = connect(send_socket,
+ remote_res->ai_addr,
+ remote_res->ai_addrlen)) == INVALID_SOCKET) {
+ if (SOCKET_EINTR(ret)) {
+ /* we interpret this to mean that the test is supposed to be
+ over, so return a value of -1 to the caller */
+ return -1;
+ }
+ if ((SOCKET_EADDRINUSE(ret)) || SOCKET_EADDRNOTAVAIL(ret) || dont_give_up) {
+ /* likely something our explicit bind() would have caught in
+ the past, so go get another port, via create_data_socket.
+ yes, this is a bit more overhead than before, but the
+ condition should be rather rare. we only get a new port if
+ this was a connection-including test like TCP_CRR or
+ TCP_CC. Otherwise we need to return an error. raj
+ 2008-01-08 */
+ return -2;
+ }
+ else
+ /* -3 means there was an error */
+ return -3;
+ }
+ return 0;
+}
+
+static
+int send_pktinfo(SOCKET data_socket, char *buffer, int len, struct sockaddr *destination, int destlen) {
+#ifdef IP_PKTINFO
+ struct msghdr msg;
+ struct iovec iovec[1];
+ char msg_control[512];
+ struct cmsghdr *cmsg;
+ int cmsg_space = 0;
+
+ iovec[0].iov_base = buffer;
+ iovec[0].iov_len = len;
+ msg.msg_name = destination;
+ msg.msg_namelen = destlen;
+ msg.msg_iov = iovec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+ msg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (have_pktinfo) {
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
+ *(struct in_pktinfo*)CMSG_DATA(cmsg) = in_pktinfo;
+ cmsg_space += CMSG_SPACE(sizeof(in_pktinfo));
+ }
+ msg.msg_controllen = cmsg_space;
+ return sendmsg(data_socket, &msg, 0);
+#else
+ return -1;
+#endif /* IP_PKTINFO */
+}
+
+
+int
+send_data(SOCKET data_socket, struct ring_elt *send_ring, uint32_t bytes_to_send, struct sockaddr *destination, int destlen, int protocol) {
+
+ int len;
+
+ /* if the user has supplied a destination, we use sendto, otherwise
+ we use send. we ass-u-me blocking operations always, so no need
+ to check for eagain or the like. */
+
+ if (debug > 2) {
+ fprintf(where,
+ "%s sock %d, ring elt %p, bytes %d, dest %p, len %d\n",
+ __FUNCTION__,
+ data_socket,
+ send_ring,
+ bytes_to_send,
+ destination,
+ destlen);
+ fflush(where);
+ }
+
+ if (destination) {
+ if (have_pktinfo) {
+ len = send_pktinfo(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send,
+ destination,
+ destlen);
+ }
+ else {
+ len = sendto(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send,
+#if defined(MSG_FASTOPEN)
+ (use_fastopen && protocol == IPPROTO_TCP) ? MSG_FASTOPEN : 0,
+#else
+ 0,
+#endif
+ destination,
+ destlen);
+ }
+ }
+ else {
+ if (!use_write) {
+ len = send(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send,
+ 0);
+ }
+ else {
+#ifndef WIN32
+ len = write(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send);
+#else
+ fprintf(where,"I'm sorry Dave I cannot write() under Windows\n");
+ fflush(where);
+ return -3;
+#endif
+ }
+ }
+ if(len != bytes_to_send) {
+ /* don't forget that some platforms may do a partial send upon
+ receipt of the interrupt and not return an EINTR... */
+ if (SOCKET_EINTR(len) || (len >= 0))
+ {
+ /* we hit the end of a timed test. */
+ return -1;
+ }
+ /* if this is UDP it is possible to receive an ENOBUFS on the send
+ call and it would not be a fatal error. of course if we were
+ to return 0 then it would make the test think it was over when
+ it really wasn't. the question becomes what to do. for the
+ time being, the answer will likely be to return something like
+ -2 to indicate a non-fatal error happened on the send and let
+ the caller figure it out :) we won't actually check to see if
+ this is UDP - it is the author's experience in many, Many, MANY
+ years that the only time an ENOBUFS has been returned in a
+ netperf test has been with UDP. famous last words :) */
+ if (errno == ENOBUFS)
+ return -2;
+ else {
+ fprintf(where,"%s: data send error: %s (errno %d)\n",
+ __FUNCTION__, strerror(errno), errno);
+ return -3;
+ }
+ }
+ return len;
+}
+
+#if defined(__linux)
+static int
+recv_data_no_copy(SOCKET data_socket, struct ring_elt *recv_ring, uint32_t bytes_to_recv, struct sockaddr *source, netperf_socklen_t *sourcelen, uint32_t flags, uint32_t *num_receives) {
+
+#ifndef SPLICE_F_MOVE
+# define SPLICE_F_MOVE 0x01
+#endif
+#ifndef SPLICE_F_NONBLOCK
+# define SPLICE_F_NONBLOCK 0x02
+#endif
+
+ static int pfd[2] = {-1, -1};
+ static int fdnull = -1;
+
+
+ char *temp_message_ptr;
+ int bytes_left;
+ int bytes_recvd;
+ int my_recvs;
+ int my_flags = SPLICE_F_MOVE | SPLICE_F_NONBLOCK; /* values
+ suggested by
+ Eric Dumazet */
+ int ret;
+
+ if (pfd[0] == -1) {
+ if (pipe(pfd)) {
+ fprintf(where,
+ "%s pipe call failed with errno %d '%s'\n",
+ __FUNCTION__,
+ errno,
+ strerror(errno));
+ return -4; /* this will cause recv_data to do things the
+ old-fashioned way for the test */
+ }
+ if ((fdnull = open("/dev/null",O_WRONLY)) == -1) {
+ fprintf(where,
+ "%s open call failed with errno %d '%s'\n",
+ __FUNCTION__,
+ errno,
+ strerror(errno));
+ return -4;
+ }
+ }
+
+ /* receive data off the data_socket, ass-u-me-ing a blocking socket
+ all the way!-) 2008-01-08 */
+ my_recvs = 0;
+ bytes_left = bytes_to_recv;
+
+ if (debug > 1) {
+ fprintf(where,
+ "%s sock %d, ring elt %p, bytes %d, source %p, srclen %d, flags %x, num_recv %p\n",
+ __FUNCTION__,
+ data_socket,
+ recv_ring,
+ bytes_to_recv,
+ source,
+ (source != NULL) ? *sourcelen : -1,
+ flags,
+ num_receives);
+ fflush(where);
+ }
+ do {
+
+ bytes_recvd = splice(data_socket,
+ NULL,
+ pfd[1],
+ NULL,
+ bytes_left,
+ my_flags);
+
+
+ if (bytes_recvd > 0) {
+ /* per Eric Dumazet, we should just let this second splice call
+ move as many bytes as it can and not worry about how much.
+ this should make the call more robust when made on a system
+ under memory pressure */
+ splice(pfd[0], NULL, fdnull, NULL, 1 << 30, my_flags);
+ bytes_left -= bytes_recvd;
+ }
+ else {
+ break;
+ }
+ my_recvs++; /* should the pair of splices count as one? */
+ } while ((bytes_left > 0) && (flags & NETPERF_WAITALL));
+
+ *num_receives = my_recvs;
+
+ /* OK, we are out of the loop - now what? */
+ if (bytes_recvd < 0) {
+ /* did the timer hit, or was there an error? */
+ if (SOCKET_EINTR(bytes_recvd))
+ {
+ /* We hit the end of a timed test. */
+ return -1;
+ }
+ /* it was a hard error */
+ return -3;
+ }
+
+
+ /* this looks a little funny, but should be correct. if we had
+ NETPERF_WAITALL set and we got here, it means we got all the
+ bytes of the request/response. otherwise we would have hit the
+ error or end of test cases. if NETPERF_WAITALL isn't set, this
+ is a STREAM test, and we will have only made one call to recv, so
+ bytes_recvd will be accurate. */
+ if (bytes_left)
+ return bytes_recvd;
+ else
+ return bytes_to_recv;
+
+}
+
+#endif
+
+static
+int recv_pktinfo(SOCKET data_socket, char *message_ptr, int bytes_to_recv, int my_flags, struct sockaddr *source, netperf_socklen_t *sourcelen) {
+
+#ifdef IP_PKTINFO
+ struct iovec my_iovec;
+ struct msghdr my_header;
+ struct cmsghdr *cmsg;
+ struct in_pktinfo *pktinfo;
+
+ char control_buf[512];
+ int onoff = 1;
+ int ret;
+
+ my_iovec.iov_base = message_ptr;
+ my_iovec.iov_len = bytes_to_recv;
+
+ my_header.msg_name = source;
+ my_header.msg_namelen = *sourcelen;
+ my_header.msg_iov = &my_iovec;
+ my_header.msg_iovlen = 1;
+ my_header.msg_control = control_buf;
+ my_header.msg_controllen = sizeof(control_buf);
+
+ /* not going to bother checking, if it doesn't work we are no
+ worse-off than we were before. we are going to ignore IPv6 for
+ the time being */
+ setsockopt(data_socket, IPPROTO_IP, IP_PKTINFO, &onoff, sizeof(onoff));
+
+ ret = recvmsg(data_socket, &my_header, 0);
+
+ if (ret >= 0) {
+ struct sockaddr_in me;
+ struct sockaddr_in clear;
+ netperf_socklen_t melen = sizeof(me);
+ for (cmsg = CMSG_FIRSTHDR(&my_header);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&my_header, cmsg)) {
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+ in_pktinfo = *(struct in_pktinfo *)CMSG_DATA(cmsg);
+ have_pktinfo = 1;
+ }
+ }
+ }
+
+ onoff = 0;
+ setsockopt(data_socket, IPPROTO_IP, IP_PKTINFO, &onoff, sizeof(onoff));
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+
+
+int
+recv_data(SOCKET data_socket, struct ring_elt *recv_ring, uint32_t bytes_to_recv, struct sockaddr *source, netperf_socklen_t *sourcelen, uint32_t flags, uint32_t *num_receives) {
+
+ char *temp_message_ptr;
+ int bytes_left;
+ int bytes_recvd;
+ int my_recvs;
+ int my_flags = 0; /* will we one day want to set MSG_WAITALL? */
+
+#if defined(__linux)
+ int ret;
+ if (loc_rcvavoid == 1) {
+ ret = recv_data_no_copy(data_socket, recv_ring, bytes_to_recv, source, sourcelen, flags, num_receives);
+ if (ret != -4)
+ return ret;
+ else
+ loc_rcvavoid = 0;
+ }
+#endif
+
+ /* receive data off the data_socket, ass-u-me-ing a blocking socket
+ all the way!-) 2008-01-08 */
+ my_recvs = 0;
+ bytes_left = bytes_to_recv;
+ temp_message_ptr = recv_ring->buffer_ptr;
+
+ if (debug > 1) {
+ fprintf(where,
+ "%s sock %d, ring elt %p, bytes %d, source %p, srclen %d, flags %x, num_recv %p\n",
+ __FUNCTION__,
+ data_socket,
+ recv_ring,
+ bytes_to_recv,
+ source,
+ (source != NULL) ? *sourcelen : -1,
+ flags,
+ num_receives);
+ fflush(where);
+ }
+ do {
+ if (source) {
+ /* call recvfrom it does look a little silly here inside the do
+ while, but I think it is ok - a UDP or other DGRAM or
+ SEQPACKET (?) socket, which should be the only time we
+ pass-in a source pointer will have a semantic that should get
+ us out of the dowhile on the first call anyway. if it
+ turns-out not to be the case, then we can hoist the if above
+ the do and put the dowhile in the else. */
+ if (use_pktinfo) {
+ bytes_recvd = recv_pktinfo(data_socket,
+ temp_message_ptr,
+ bytes_left,
+ my_flags,
+ source,
+ sourcelen);
+ use_pktinfo = 0;
+ }
+ else {
+ bytes_recvd = recvfrom(data_socket,
+ temp_message_ptr,
+ bytes_left,
+ my_flags,
+ source,
+ sourcelen);
+ }
+ }
+ else {
+ /* just call recv */
+ bytes_recvd = recv(data_socket,
+ temp_message_ptr,
+ bytes_left,
+ my_flags);
+ }
+ if (bytes_recvd > 0) {
+ bytes_left -= bytes_recvd;
+ temp_message_ptr += bytes_recvd;
+ }
+ else {
+ break;
+ }
+ my_recvs++;
+ } while ((bytes_left > 0) && (flags & NETPERF_WAITALL));
+
+ *num_receives = my_recvs;
+
+ /* OK, we are out of the loop - now what? */
+ if (bytes_recvd < 0) {
+ /* did the timer hit, or was there an error? */
+ if (SOCKET_EINTR(bytes_recvd))
+ {
+ /* We hit the end of a timed test. */
+ return -1;
+ }
+ if (SOCKET_EAGAIN(bytes_recvd) ||
+ SOCKET_EWOULDBLOCK(bytes_recvd)) {
+ return -2;
+ }
+ /* it was a hard error */
+ return -3;
+ }
+
+
+ /* this looks a little funny, but should be correct. if we had
+ NETPERF_WAITALL set and we got here, it means we got all the
+ bytes of the request/response. otherwise we would have hit the
+ error or end of test cases. if NETPERF_WAITALL isn't set, this
+ is a STREAM test, and we will have only made one call to recv, so
+ bytes_recvd will be accurate. */
+ if (bytes_left)
+ return bytes_recvd;
+ else
+ return bytes_to_recv;
+
+}
+
+
+int
+close_data_socket(SOCKET data_socket, struct sockaddr *peer, int peerlen, int protocol)
+{
+
+ int ret;
+ char buffer[4];
+
+ if (debug) {
+ fprintf(where,
+ "%s sock %d peer %p peerlen %d protocol %d\n",
+ __FUNCTION__,
+ data_socket,
+ peer,
+ peerlen,
+ protocol);
+ fflush(where);
+ }
+
+ if (protocol == IPPROTO_UDP) {
+ /* try to give the remote a signal. what this means if we ever
+ wanted to actually send zero-length messages remains to be seen
+ :) */
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (peer)
+ ret = sendto(data_socket,
+ buffer,
+ 0,
+ 0,
+ peer,
+ peerlen);
+ else
+ ret = send(data_socket,
+ buffer,
+ 0,
+ 0);
+ if (SOCKET_EINTR(ret)) {
+ close(data_socket);
+ return -1;
+ }
+ }
+ }
+ ret = close(data_socket);
+
+ if (SOCKET_EINTR(ret)) {
+ /* end of test */
+ return -1;
+ }
+ else if (ret == 0) {
+ return ret;
+ }
+ else
+ return -3;
+
+}
+
+int
+disconnect_data_socket(SOCKET data_socket, int initiate, int do_close, struct sockaddr *peer, int peerlen)
+{
+
+ char buffer[4];
+ int bytes_recvd;
+
+ if (debug) {
+ fprintf(where,
+ "%s sock %d init %d do_close %d protocol %d\n",
+ __FUNCTION__,
+ data_socket,
+ initiate,
+ do_close,
+ protocol);
+ fflush(where);
+ }
+
+ /* at some point we'll need to abstract this a little. for now, if
+ the protocol is UDP, we try to send some number of zero-length
+ datagrams to allow the remote to get out of its loop without
+ having to wait for the padded timer to expire. if it isn't UDP,
+ we assume a reliable connection and can do the usual graceful
+ shutdown thing */
+
+ /* this needs to be revisited for the netperf receiving case when
+ the test is terminated by a Ctrl-C. raj 2012-01-24 */
+
+ if (protocol != IPPROTO_UDP) {
+ if (initiate)
+ shutdown(data_socket, SHUT_WR);
+
+ /* we are expecting to get either a return of zero indicating
+ connection close, or an error. of course, we *may* never
+ receive anything from the remote which means we probably really
+ aught to have a select here but until we are once bitten we
+ will remain twice bold. */
+ bytes_recvd = recv(data_socket,
+ buffer,
+ 1,
+ 0);
+
+ if (bytes_recvd != 0) {
+ /* connection close, call close. we assume that the requisite
+ number of bytes have been received */
+ if (SOCKET_EINTR(bytes_recvd))
+ {
+ /* We hit the end of a timed test. */
+ return -1;
+ }
+ return -3;
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (peer)
+ bytes_recvd = sendto(data_socket,
+ buffer,
+ 0,
+ 0,
+ peer,
+ peerlen);
+ else
+ bytes_recvd = send(data_socket,
+ buffer,
+ 0,
+ 0);
+ /* we only really care if the timer expired on us */
+ if (SOCKET_EINTR(bytes_recvd)) {
+ if (do_close)
+ close(data_socket);
+ return -1;
+ }
+ }
+ }
+
+ if (do_close)
+ close(data_socket);
+
+ return 0;
+}
+
+#ifdef HAVE_LINUX_TCP_H
+static void
+dump_tcp_info(struct tcp_info *tcp_info)
+{
+
+ fprintf(stderr,
+ "tcpi_rto %d tcpi_ato %d tcpi_pmtu %d tcpi_rcv_ssthresh %d\n"
+ "tcpi_rtt %d tcpi_rttvar %d tcpi_snd_ssthresh %d tpci_snd_cwnd %d\n"
+ "tcpi_reordering %d tcpi_total_retrans %d\n",
+ tcp_info->tcpi_rto,
+ tcp_info->tcpi_ato,
+ tcp_info->tcpi_pmtu,
+ tcp_info->tcpi_rcv_ssthresh,
+ tcp_info->tcpi_rtt,
+ tcp_info->tcpi_rttvar,
+ tcp_info->tcpi_snd_ssthresh,
+ tcp_info->tcpi_snd_cwnd,
+ tcp_info->tcpi_reordering,
+ tcp_info->tcpi_total_retrans);
+
+ return;
+}
+
+#endif
+
+static int
+get_transport_retrans(SOCKET socket, int protocol) {
+
+#ifdef HAVE_LINUX_TCP_H
+ struct tcp_info tcp_info;
+
+ int ret;
+ netperf_socklen_t infosize;
+
+ if (protocol != IPPROTO_TCP)
+ return -1;
+
+ infosize = sizeof(struct tcp_info);
+
+ if ((ret = getsockopt(socket,protocol,TCP_INFO,&tcp_info,&infosize)) < 0) {
+ if (debug) {
+ fprintf(where,
+ "%s: getsockopt errno %d %s\n",
+ __FUNCTION__,
+ errno,
+ strerror(errno));
+ fflush(where);
+ }
+ return -1;
+ }
+ else {
+
+ /* we assume that if we have LINUX_TCP_H we also have getenv */
+ if (debug > 1 || getenv("DUMP_TCP_INFO")) {
+ dump_tcp_info(&tcp_info);
+ }
+ return tcp_info.tcpi_total_retrans;
+ }
+
+
+#else
+ return -1;
+#endif
+}
+
+
+static void
+get_transport_info(SOCKET socket, int *mss, int protocol)
+{
+
+ netperf_socklen_t sock_opt_len;
+ int option;
+ sock_opt_len = sizeof(netperf_socklen_t);
+
+ switch (protocol) {
+#if defined(IPPROTO_TCP) && defined(TCP_MAXSEG)
+ case IPPROTO_TCP:
+ option = TCP_MAXSEG;
+ break;
+#endif
+
+#if defined(IPPROTO_SCTP) && defined(SCTP_MAXSEG)
+ case IPPROTO_SCTP:
+ option = SCTP_MAXSEG;
+ break;
+#endif
+ default:
+ *mss = -1;
+ return;
+ }
+
+ if (getsockopt(socket,
+ protocol,
+ option,
+ (char *)mss,
+ &sock_opt_len) == SOCKET_ERROR) {
+ fprintf(where,
+ "%s: getsockopt: errno %d\n",
+ __FUNCTION__,
+ errno);
+ fflush(where);
+ *mss = -1;
+ }
+
+}
+
+static void
+get_transport_cong_control(SOCKET socket, int protocol, char cong_control[], int len)
+{
+#ifdef TCP_CONGESTION
+ int my_len = len;
+ if (protocol != IPPROTO_TCP) {
+ strncpy(cong_control,"TCP Only",len);
+ }
+ else if (getsockopt(socket,
+ protocol, TCP_CONGESTION, cong_control, &my_len) ==
+ SOCKET_ERROR) {
+ snprintf(cong_control,len,"%d errno",errno);
+ }
+#else
+ strncpy(cong_control,"Unavailable",len);
+#endif
+ cong_control[len-1] = '\0';
+}
+
+static void
+set_transport_cong_control(SOCKET socket, int protocol, char cong_control[], int len)
+{
+#ifdef TCP_CONGESTION
+ if (protocol == IPPROTO_TCP) {
+ /* if it fails, we'll pick that up via the subsequent "get" */
+ setsockopt(socket, protocol, TCP_CONGESTION, cong_control, len);
+ }
+#endif
+}
+
+static void
+set_receive_timeout(SOCKET sock, int timeout)
+{
+#ifdef SO_RCVTIMEO
+#ifndef WIN32
+ struct timeval foo;
+
+ foo.tv_sec = timeout;
+ foo.tv_usec = 0;
+
+ if (setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&foo,sizeof(foo)) < 0) {
+ if (debug) {
+ fprintf(where,"Note - attempt to set a receive timeout on the data socket failed with errno %d (%s)\n",
+ errno,
+ strerror(errno));
+ fflush(where);
+ }
+ }
+#endif
+#endif
+}
+
+static SOCKET
+omni_create_data_socket(struct addrinfo *res)
+{
+ SOCKET temp_socket;
+
+ temp_socket = create_data_socket(res);
+
+ if (temp_socket != SOCKET_ERROR) {
+ if (local_cong_control_req[0] != '\0') {
+ set_transport_cong_control(temp_socket,
+ res->ai_protocol,
+ local_cong_control_req,
+ sizeof(local_cong_control_req));
+ }
+
+ if ((res->ai_protocol == IPPROTO_UDP) &&
+ (receive_timeout != -1)) {
+ set_receive_timeout(temp_socket, receive_timeout);
+ }
+
+ if (socket_debug) {
+ int one = 1;
+ setsockopt(temp_socket,
+ SOL_SOCKET,
+ SO_DEBUG,
+ &one,
+ sizeof(one));
+ }
+ }
+ return temp_socket;
+}
+/* choosing the default send size is a trifle more complicated than it
+ used to be as we have to account for different protocol limits */
+
+#define UDP_LENGTH_MAX (0xFFFF - 28)
+
+static int
+choose_send_size(int lss, int protocol) {
+
+ int send_size;
+
+ if (lss > 0) {
+ send_size = lss_size;
+
+ /* we will assume that everyone has IPPROTO_UDP and thus avoid an
+ issue with Windows using an enum */
+ if ((protocol == IPPROTO_UDP) && (send_size > UDP_LENGTH_MAX))
+ send_size = UDP_LENGTH_MAX;
+
+ }
+ else {
+ send_size = 4096;
+ }
+ return send_size;
+}
+
+/* brain dead simple way to get netperf to emit a uuid. sadly, by this
+ point we will have already established the control connection but
+ those are the breaks. we do _NOT_ include a trailing newline
+ because we want to be able to use this in a script */
+
+void
+print_uuid(char remote_host[])
+{
+ printf("%s",test_uuid);
+}
+#if defined(__linux)
+/*
+ * Linux has this odd behavior where if the socket buffers are larger
+ * than a device's txqueuelen, the kernel will silently drop transmits
+ * which would not fit into the tx queue, and not pass an ENOBUFS
+ * error back to the application. As a result, a UDP stream test can
+ * report absurd transmit bandwidths (like 20Gb/s on a 1GbE NIC).
+ * This behavior can be avoided if you request extended error
+ * reporting on the socket. This is done by setting the IP_RECVERR
+ * socket option at the IP level.
+ */
+static void
+enable_enobufs(int s)
+{
+ struct protoent *pr;
+ int on = 1;
+
+ if ((pr = getprotobyname("ip")) == NULL) {
+ fprintf(where, "%s failed: getprotobyname\n",__FUNCTION__);
+ fflush(where);
+ return;
+ }
+ if (setsockopt(s, pr->p_proto, IP_RECVERR, (char *)&on, sizeof(on)) < 0) {
+ fprintf(where, "%s failed: setsockopt (errno %d)\n",__FUNCTION__,errno);
+ fflush(where);
+ return;
+ }
+}
+#endif
+
+void
+set_omni_request_flags(struct omni_request_struct *omni_request) {
+
+ /* we have no else clauses here because we previously set flags
+ to zero above raj 20090803 */
+ if (rem_nodelay)
+ omni_request->flags |= OMNI_NO_DELAY;
+
+ if (remote_use_sendfile)
+ omni_request->flags |= OMNI_USE_SENDFILE;
+
+ if (connection_test)
+ omni_request->flags |= OMNI_CONNECT_TEST;
+
+ if (remote_checksum_off)
+ omni_request->flags |= OMNI_CHECKSUM_OFF;
+
+ if (remote_cpu_usage)
+ omni_request->flags |= OMNI_MEASURE_CPU;
+
+ if (routing_allowed)
+ omni_request->flags |= OMNI_ROUTING_ALLOWED;
+
+ if (desired_output_groups & OMNI_WANT_REM_IFNAME)
+ omni_request->flags |= OMNI_WANT_IFNAME;
+
+ if (desired_output_groups & OMNI_WANT_REM_IFSLOT)
+ omni_request->flags |= OMNI_WANT_IFSLOT;
+
+ if (desired_output_groups & OMNI_WANT_REM_IFIDS)
+ omni_request->flags |= OMNI_WANT_IFIDS;
+
+ if (desired_output_groups & OMNI_WANT_REM_DRVINFO)
+ omni_request->flags |= OMNI_WANT_DRVINFO;
+
+ if (desired_output_groups & OMNI_WANT_REM_CONG)
+ omni_request->flags |= OMNI_WANT_REM_CONG;
+
+ if (use_fastopen)
+ omni_request->flags |= OMNI_FASTOPEN;
+
+ if (want_use_pktinfo)
+ omni_request->flags |= OMNI_USE_PKTINFO;
+
+ if (want_defer_accept)
+ omni_request->flags |= OMNI_WANT_DEFER_ACCEPT;
+
+}
+
+
+/* this code is intended to be "the two routines to run them all" for
+ BSDish sockets. it comes about as part of a desire to shrink the
+ code footprint of netperf and to avoid having so many blessed
+ routines to alter as time goes by. the downside is there will be
+ more "ifs" than there were before. raj 2008-01-07 */
+
+void
+send_omni_inner(char remote_host[], unsigned int legacy_caller, char header_str[])
+{
+
+ int ret,rret;
+ int connected = 0;
+ int timed_out = 0;
+ int pad_time = 0;
+
+ struct ring_elt *send_ring;
+ struct ring_elt *recv_ring;
+
+ struct sockaddr_storage remote_addr;
+ struct sockaddr_storage my_addr;
+ int remote_addr_len = sizeof(remote_addr);
+ netperf_socklen_t my_addr_len = sizeof(my_addr);
+
+ SOCKET data_socket;
+ int need_socket;
+
+ uint32_t temp_recvs;
+ char tmpfmt;
+
+ struct addrinfo *local_res;
+ struct addrinfo *remote_res;
+
+ struct omni_request_struct *omni_request;
+ struct omni_response_struct *omni_response;
+ struct omni_results_struct *omni_result;
+
+#ifdef WANT_FIRST_BURST
+ int requests_outstanding = 0;
+#endif
+
+ omni_request =
+ (struct omni_request_struct *)netperf_request.content.test_specific_data;
+ omni_response =
+ (struct omni_response_struct *)netperf_response.content.test_specific_data;
+ omni_result =
+ (struct omni_results_struct *)netperf_response.content.test_specific_data;
+
+
+ if (keep_histogram) {
+ if (first_burst_size > 0)
+ time_hist = HIST_new_n(first_burst_size + 1);
+ else
+ time_hist = HIST_new_n(1);
+ }
+
+ /* since we are now disconnected from the code that established the
+ control socket, and since we want to be able to use different
+ protocols and such, we are passed the name of the remote host and
+ must turn that into the test specific addressing information. */
+
+ complete_addrinfos(&remote_res,
+ &local_res,
+ remote_host,
+ socket_type,
+ protocol,
+ 0);
+
+ if ( print_headers ) {
+ print_top_test_header(header_str,local_res,remote_res);
+ }
+
+ /* initialize a few counters */
+
+ need_socket = 1;
+
+ if (connection_test)
+ pick_next_port_number(local_res,remote_res);
+
+
+ /* If the user has requested cpu utilization measurements, we must
+ calibrate the cpu(s). We will perform this task within the tests
+ themselves. If the user has specified the cpu rate, then
+ calibrate_local_cpu will return rather quickly as it will have
+ nothing to do. If local_cpu_rate is zero, then we will go through
+ all the "normal" calibration stuff and return the rate back.*/
+
+ if (local_cpu_usage) {
+ local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+ }
+
+ confidence_iteration = 1;
+ init_stat();
+
+ send_ring = NULL;
+ recv_ring = NULL;
+
+ /* you will keep running the test until you get it right! :) */
+ while (((confidence < 0) && (confidence_iteration <= iteration_max)) ||
+ (confidence_iteration <= iteration_min)) {
+
+ trans_completed = 0;
+ bytes_xferd = 0.0;
+ remote_bytes_xferd = 0.0;
+ times_up = 0;
+ bytes_sent = 0;
+ bytes_received = 0;
+ local_send_calls = 0;
+ local_receive_calls = 0;
+
+ /* since we are tracking the number of outstanding requests for
+ timestamping purposes, and since the previous iteration of
+ using confidence intervals may not have completed all of them,
+ we now need to forget about them or we will mistakenly fill our
+ tracking array. raj 2011-03-14 */
+ if (keep_histogram) {
+ HIST_purge(time_hist);
+ }
+
+#ifdef WANT_FIRST_BURST
+ /* we have to remember to reset the number of transactions
+ outstanding and the "congestion window for each new
+ iteration. raj 2006-01-31. */
+ requests_outstanding = 0;
+#endif
+
+ /* if the command-line included requests to randomize the IP
+ addresses, then honor it. of course, this may not work all that
+ well for some tests... raj 20101129 */
+ if (local_mask_len)
+ random_ip_address(local_res, local_mask_len);
+ if (remote_mask_len)
+ random_ip_address(remote_res, remote_mask_len);
+
+ data_socket = omni_create_data_socket(local_res);
+
+ if (data_socket == INVALID_SOCKET) {
+ perror("netperf: send_omni: unable to create data socket");
+ exit(1);
+ }
+#if defined(__linux)
+ /* we really only need this for a UDP_STREAM test. we particularly
+ do not want it for a CC or CRR test. raj 2012-08-06 */
+ if ((protocol == IPPROTO_UDP) &&
+ NETPERF_XMIT_ONLY(direction)) {
+ enable_enobufs(data_socket);
+ }
+#endif
+ need_socket = 0;
+
+ /* we need to consider if this is a request/response test, if we
+ are receiving, if we are sending, etc, when setting-up our recv
+ and send buffer rings. we should only need to do this once, and
+ that would be when the relevant _ring variable is NULL. raj
+ 2008-01-18 */
+ if (direction & NETPERF_XMIT) {
+ if (is_multicast_addr(remote_res)) {
+ set_multicast_ttl(data_socket);
+ }
+
+ if (NULL == send_ring) {
+ if (req_size > 0) {
+ /* request/response test */
+ if (send_width == 0) send_width = 1;
+ bytes_to_send = req_size;
+ }
+ else {
+ /* stream test */
+ if (send_size == 0) {
+ send_size = choose_send_size(lss_size,protocol);
+ }
+ if (send_width == 0)
+ send_width = (lss_size/send_size) + 1;
+ if (send_width == 1) send_width++;
+ bytes_to_send = send_size;
+ }
+
+ send_ring = allocate_buffer_ring(send_width,
+ bytes_to_send,
+ local_send_align,
+ local_send_offset);
+ if (debug) {
+ fprintf(where,
+ "%s: %d entry send_ring obtained...\n",
+ __FUNCTION__,
+ send_width);
+ }
+ }
+ }
+
+ if (direction & NETPERF_RECV) {
+ /* do we need to join a multicast group? */
+ if (is_multicast_addr(local_res)) {
+ join_multicast_addr(data_socket, local_res);
+ }
+
+ /* do we need to allocate a recv_ring? */
+ if (NULL == recv_ring) {
+ if (rsp_size > 0) {
+ if (recv_width == 0) recv_width = 1;
+ bytes_to_recv = rsp_size;
+ }
+ else {
+ /* stream test */
+ if (recv_size == 0) {
+ if (lsr_size > 0) {
+ recv_size = lsr_size;
+ }
+ else {
+ recv_size = 4096;
+ }
+ }
+ if (recv_width == 0) {
+ recv_width = (lsr_size/recv_size) + 1;
+ if (recv_width == 1) recv_width++;
+ }
+ bytes_to_recv = recv_size;
+ }
+
+ recv_ring = allocate_buffer_ring(recv_width,
+ bytes_to_recv,
+ local_recv_align,
+ local_recv_offset);
+ if (debug) {
+ fprintf(where,
+ "%s: %d entry recv_ring obtained...\n",
+ __FUNCTION__,
+ recv_width);
+ }
+ }
+ }
+
+ if (!no_control) {
+
+ /* Tell the remote end to do a listen or otherwise prepare for
+ what is to come. The server alters the socket paramters on the
+ other side at this point, hence the reason for all the values
+ being passed in the setup message. If the user did not specify
+ any of the parameters, they will be passed as values which will
+ indicate to the remote that no changes beyond the system's
+ default should be used. Alignment is the exception, it will
+ default to 8, which will probably be no alignment
+ alterations. */
+
+ netperf_request.content.request_type = DO_OMNI;
+ omni_request->flags = 0;
+ omni_request->send_buf_size = rss_size_req;
+ omni_request->send_size = remote_send_size_req;
+ omni_request->send_alignment = remote_send_align;
+ omni_request->send_offset = remote_send_offset;
+ omni_request->send_width = send_width;
+ omni_request->request_size = req_size;
+
+ omni_request->recv_buf_size = rsr_size_req;
+ omni_request->receive_size = remote_recv_size_req;
+ omni_request->recv_alignment = remote_recv_align;
+ omni_request->recv_offset = remote_recv_offset;
+ omni_request->recv_width = recv_width;
+ omni_request->response_size = rsp_size;
+ omni_request->socket_prio = remote_socket_prio;
+ omni_request->socket_tos = remote_socket_tos;
+
+ set_omni_request_flags(omni_request);
+
+ /* perhaps this should be made conditional on
+ remote_cong_control_req[0] not being NULL? */
+ strncpy(omni_request->cong_control,
+ remote_cong_control_req,
+ sizeof(omni_request->cong_control));
+ omni_request->cong_control[sizeof(omni_request->cong_control) - 1] =
+ '\0';
+
+ if (want_keepalive)
+ omni_request->flags |= OMNI_WANT_KEEPALIVE;
+
+ omni_request->cpu_rate = remote_cpu_rate;
+ if (test_time)
+ omni_request->test_length = test_time;
+ else
+ omni_request->test_length = test_trans * -1;
+ omni_request->so_rcvavoid = rem_rcvavoid;
+ omni_request->so_sndavoid = rem_sndavoid;
+ omni_request->send_dirty_count = rem_dirty_count;
+ omni_request->recv_dirty_count = rem_dirty_count;
+ omni_request->recv_clean_count = rem_clean_count;
+
+ omni_request->data_port = atoi(remote_data_port);
+ omni_request->ipfamily = af_to_nf(remote_res->ai_family);
+ omni_request->socket_type = hst_to_nst(socket_type);
+ omni_request->protocol = protocol;
+
+ omni_request->interval_burst = remote_interval_burst;
+ omni_request->interval_usecs = remote_interval_usecs;
+
+ omni_request->direction = 0;
+ /* yes, the sense here is correct - if we are transmitting, they
+ receive, if we are receiving, they are transmitting... */
+ if (direction & NETPERF_XMIT)
+ omni_request->direction |= NETPERF_RECV;
+ if (direction & NETPERF_RECV)
+ omni_request->direction |= NETPERF_XMIT;
+
+ /* some tests may require knowledge of our local addressing. such
+ tests will for the time being require that the user specify a
+ local IP/name so we can extract them from the data_socket. */
+ getsockname(data_socket, (struct sockaddr *)&my_addr, &my_addr_len);
+
+ ret = get_sockaddr_family_addr_port(&my_addr,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->netperf_ip,
+ &(omni_request->netperf_port));
+ ret = get_sockaddr_family_addr_port((struct sockaddr_storage *)remote_res->ai_addr,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->netserver_ip,
+ &(omni_request->data_port));
+ /* if the user didn't explicitly set the remote data address we
+ don't want to pass along the one we picked implicitly, or a
+ netserver sitting behind a (BLETCH) NAT will be asked to try
+ to bind to the "public" IP. */
+ if (!explicit_data_address) {
+ omni_request->netserver_ip[0] = 0;
+ omni_request->netserver_ip[1] = 0;
+ omni_request->netserver_ip[2] = 0;
+ omni_request->netserver_ip[3] = 0;
+ }
+ if (debug > 1) {
+ fprintf(where,"netperf: %s: requesting OMNI test\n",__FUNCTION__);
+ }
+
+ strncpy(omni_request->fill_file,
+ remote_fill_file,
+ sizeof(omni_request->fill_file));
+
+ send_request_n(OMNI_REQUEST_CONV_CUTOFF);
+
+
+ /* the response from the remote should contain all the relevant
+ socket and other parameters we need to know for this test.
+ so, we can shove them back into the relevant variables here
+ and be on our way. */
+
+ recv_response_n(OMNI_RESPONSE_CONV_CUTOFF); /* brittle, but functional */
+
+ if (!netperf_response.content.serv_errno) {
+ rsr_size = omni_response->recv_buf_size;
+ remote_recv_size = omni_response->receive_size;
+ rss_size = omni_response->send_buf_size;
+ remote_send_size = omni_response->send_size;
+ rem_nodelay = omni_response->flags & OMNI_NO_DELAY;
+ remote_use_sendfile = omni_response->flags & OMNI_USE_SENDFILE;
+ remote_cpu_usage = omni_response->flags & OMNI_MEASURE_CPU;
+ remote_cpu_rate = omni_response->cpu_rate;
+ remote_send_width = omni_response->send_width;
+ remote_recv_width = omni_response->recv_width;
+ remote_socket_prio = omni_response->socket_prio;
+ remote_socket_tos = omni_response->socket_tos;
+
+ /* make sure that port numbers are in network order because
+ recv_response will have put everything into host order */
+ set_port_number(remote_res,
+ (unsigned short)omni_response->data_port);
+
+ if (debug) {
+ fprintf(where,"remote listen done.\n");
+ fprintf(where,"remote port is %u\n",get_port_number(remote_res));
+ fflush(where);
+ }
+ }
+ else {
+ Set_errno(netperf_response.content.serv_errno);
+ fprintf(where,
+ "netperf: remote error %d",
+ netperf_response.content.serv_errno);
+ perror("");
+ fflush(where);
+ exit(-1);
+ }
+
+ }
+
+#ifdef WANT_DEMO
+ /* at some point we will have to be more clever about this, but
+ for now we won't */
+
+ demo_rr_setup(100);
+#endif
+
+ /* if we are not a connectionless protocol, we need to connect. at
+ some point even if we are a connectionless protocol, we may
+ still want to "connect" for convenience raj 2008-01-14 */
+ need_to_connect = (protocol != IPPROTO_UDP) || local_connected;
+
+ /* possibly wait just a moment before actually starting - used
+ mainly when one is doing many many many concurrent netperf
+ tests */
+ WAIT_BEFORE_DATA_TRAFFIC();
+
+ /* Set-up the test end conditions. For tests over a
+ "reliable/connection-oriented" transport (eg TCP, SCTP, etc)
+ this can be either time or byte/transaction count based. for
+ unreliable transport or connection tests it can only be time
+ based. having said that, we rely entirely on other code to
+ enforce this before we even get here. raj 2008-01-08 */
+
+ /* enable a test_time of 0 to mean just keep running until
+ something other than alarm() generates a signal. raj
+ 2012-02-01 */
+ if ((test_time) || ((test_trans == 0) && (test_bytes == 0))) {
+ /* The user wanted to end the test after a period of time. if
+ we are a recv-only test, we need to protect ourself against
+ the remote going poof, but we want to make sure we don't
+ give-up before they finish, so we will add a PAD_TIME to the
+ timer. if we are RR or XMIT, there should be no need for
+ padding */
+ times_up = 0;
+ units_remaining = 0;
+ if ((!no_control) &&
+ (NETPERF_RECV_ONLY(direction)) &&
+ ((test_trans == 0) && (test_bytes == 0)))
+ pad_time = 0;
+ start_timer(test_time + pad_time);
+ }
+ else {
+ /* The tester wanted to send a number of bytes or exchange a
+ number of transactions. */
+ if (NETPERF_IS_RR(direction))
+ units_remaining = test_trans;
+ else
+ units_remaining = test_bytes;
+ times_up = 1;
+ }
+
+ /* grab the current time, and if necessary any starting information
+ for the gathering of CPU utilization at this end. */
+ cpu_start(local_cpu_usage);
+
+#if defined(WANT_INTERVALS)
+ INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+#ifdef WANT_DEMO
+ if (demo_mode) {
+ demo_first_timestamp();
+ }
+#endif
+
+ /* the "OR" here allows us to control test length by either
+ byte/transaction count or by timer. when the test is
+ byte/transaction count based the time test will always evaluate
+ false. when the test is controlled by time, the byte/transaction
+ count will always evaluate to false. when the test is finished
+ the whole expression will go false and we will stop sending
+ data. at least that is the plan :) raj 2008-01-08 */
+
+ while ((!times_up) || (units_remaining > 0)) {
+
+ /* we need to be careful about when we snap a timestamp
+ depending on the test parameters. this one *should* cover
+ everything but the burst request/response test - famous last
+ words of course. raj 20110111 */
+
+ if (keep_histogram) {
+ HIST_timestamp_start(time_hist);
+ }
+
+
+ again:
+
+ if (need_socket) {
+ if (connection_test)
+ pick_next_port_number(local_res,remote_res);
+
+ data_socket = omni_create_data_socket(local_res);
+
+ if (data_socket == INVALID_SOCKET) {
+ perror("netperf: send_omni: unable to create data socket");
+ exit(1);
+ }
+ need_socket = 0;
+#if defined(__linux)
+ if ((protocol == IPPROTO_UDP) &&
+ (direction & NETPERF_XMIT)) {
+ enable_enobufs(data_socket);
+ }
+#endif
+ }
+
+ /* only connect if and when we need to */
+ if (need_to_connect && !use_fastopen) {
+ /* assign to data_socket since connect_data_socket returns
+ SOCKET and not int thanks to Windows. */
+ ret = connect_data_socket(data_socket,remote_res,dont_give_up);
+ if (ret == 0) {
+ connected = 1;
+ need_to_connect = 0;
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else if ((ret == -2) && connection_test) {
+ /* transient error on a connection test means go around and
+ try again with another local port number */
+ if (debug) {
+ fprintf(where,"transient! transient! torpedo in the water!\n");
+ fflush(where);
+ }
+ close(data_socket);
+ connected = 0; /* probably redundant but what the heck... */
+ need_socket = 1;
+ need_to_connect = 1;
+ /* this will stuff the next local port number within bounds
+ into our local res, and then when the goto has us
+ allocating a new socket it will do the right thing with the
+ bind() call */
+ pick_next_port_number(local_res,remote_res);
+ /* yes Virginia, a goto. perhaps one day we will rewrite
+ the code to avoid it but for now, a goto... raj */
+ goto again;
+ }
+ else {
+ /* either this was a hard failure (-3) or a soft failure on
+ something other than a connection test */
+ perror("netperf: send_omni: connect_data_socket failed");
+ exit(1);
+ }
+ }
+
+#ifdef WANT_FIRST_BURST
+ /* Long ago and far away, on just about any *nix, one could
+ avoid having multiple requests bundled into the same TCP
+ segment simply by setting TCP_NODELAY and perhaps not trying
+ to have more outstanding at one time than our guesstimate as
+ to the TCP congestion window. In that way one could use a
+ burst mode TCP_RR test as part of trying to measure maximum
+ packets per second (PPS) on a system or through a NIC (well,
+ assuming there weren't many retransmissions anyway) These
+ days with Linux the dominant *nix and with it having made it
+ virtually impossible to do any longer, it is no longer worth
+ it to try the application-layer backflips. So, I am removing
+ them. At some point we'll simply have to enhance this code
+ to deal with multiple connections at one time, each with just
+ the one transaction in flight for our PPS testing. Multiple
+ netperfs, each with one connection and one transaction in
+ flight rapidly becomes a context-switching benchmark rather
+ than "networking". raj 2015-04-20 */
+
+ while ((first_burst_size > 0) &&
+ (requests_outstanding < first_burst_size) &&
+ (NETPERF_IS_RR(direction)) &&
+ (!connection_test)) {
+ if (debug > 1) {
+ fprintf(where,
+ "injecting, req_outstanding %d burst %d\n",
+ requests_outstanding,
+ first_burst_size);
+ }
+
+ if ((ret = send_data(data_socket,
+ send_ring,
+ bytes_to_send,
+ (connected) ? NULL : remote_res->ai_addr,
+ remote_res->ai_addrlen,
+ protocol)) != bytes_to_send) {
+ /* in theory, we should never hit the end of the test in the
+ first burst. however, in practice I have indeed seen
+ some ENOBUFS happen in some aggregate tests. so we need
+ to be a bit more sophisticated in how we handle it. raj
+ 20130516 */
+ if (ret != -2) {
+ perror("send_omni: initial burst data send error");
+ exit(-1);
+ }
+ failed_sends++;
+ }
+ else {
+ local_send_calls += 1;
+ requests_outstanding += 1;
+ }
+
+ /* yes, it seems a trifle odd having this *after* the send()
+ just above, but really this is for the next send() or
+ recv() call below or in the iteration of this loop, and the
+ first HIST_timestamp_start() call at the top of the
+ outermost loop will be for the first send() call here in
+ the burst code. clear ain't it?-) raj 20110111 */
+
+ if (keep_histogram) {
+ HIST_timestamp_start(time_hist);
+ }
+ }
+
+#endif /* WANT_FIRST_BURST */
+
+ /* if we should try to send something, then by all means, let us
+ try to send something. */
+ if (direction & NETPERF_XMIT) {
+
+ ret = send_data(data_socket,
+ send_ring,
+ bytes_to_send,
+ (connected) ? NULL : remote_res->ai_addr,
+ /* if the destination above is NULL, this is ignored */
+ remote_res->ai_addrlen,
+ protocol);
+ /* the order of these if's will seem a triffle strange, but they
+ are my best guess as to order of probabilty and/or importance
+ to the overhead raj 2008-01-09*/
+ if (ret == bytes_to_send) {
+ /* if this is a send-only test controlled by byte count we
+ decrement units_remaining by the bytes sent */
+ if (!(direction & NETPERF_RECV) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_sent += ret;
+ send_ring = send_ring->next;
+ local_send_calls++;
+ }
+ else if (ret == -2) {
+ /* what to do here -2 means a non-fatal error - probably
+ ENOBUFS and so our send didn't happen. in the old code for
+ UDP_STREAM we would just continue in the while loop. it
+ isn't clear that is what to do here, so we will simply
+ increment the failed_sends stat and fall-through. If this
+ is a UDP_STREAM style of test, the net effect should be the
+ same. if this is a UDP_RR with a really-big burst count, I
+ don't think we were checking for ENOBUFS there anyway and
+ so would have failed. Here we can just let things
+ slide. */
+ failed_sends++;
+ }
+ else if (ret == 0) {
+ /* was this a zero-byte send? if it was, then ostensibly we
+ would hit the ret == bytes_to_send case which means we'd
+ never get here as we are using blocking semantics */
+ fprintf(where,"HOW DID I GET HERE?\n");
+ fflush(where);
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else {
+ perror("netperf: send_omni: send_data failed");
+ exit(1);
+ }
+
+ }
+
+#ifdef WANT_FIRST_BURST
+ /* it isn't clear we need to check the directions here. the
+ increment should be cheaper than the conditional, and it
+ shouldn't hurt the other directions because they'll never
+ look at them. famous last words of raj 2008-01-25 */
+ requests_outstanding += 1;
+#endif
+
+#ifdef WIN32
+ /* this is used so the timer thread can close the socket out
+ from under us, which to date is the easiest/cleanest/least
+ Windows-specific way I can find to force the winsock calls to
+ return WSAEINTR with the test is over. anything that will run
+ on 95 and NT and is closer to what netperf expects from Unix
+ signals and such would be appreciated raj 1/96 */
+ win_kludge_socket = data_socket;
+#endif /* WIN32 */
+
+ if (direction & NETPERF_RECV) {
+ rret = recv_data(data_socket,
+ recv_ring,
+ bytes_to_recv,
+ (connected) ? NULL : (struct sockaddr *)&remote_addr,
+ /* if remote_addr NULL this is ignored */
+ &remote_addr_len,
+ /* if XMIT also set this is RR so waitall */
+ (direction & NETPERF_XMIT) ? NETPERF_WAITALL: 0,
+ &temp_recvs);
+ if (rret > 0) {
+ /* if this is a recv-only test controlled by byte count we
+ decrement the units_remaining by the bytes received */
+ if (!(direction & NETPERF_XMIT) && (units_remaining > 0)) {
+ units_remaining -= rret;
+ }
+ bytes_received += rret;
+ local_receive_calls += temp_recvs;
+ }
+ else if (rret == 0) {
+ /* is this the end of a test, just a zero-byte recv, or
+ something else? that is an exceedingly good question and
+ one for which I don't presently have a good answer, but
+ that won't stop me from guessing :) raj 2008-01-09 */
+ if (!((connection_test) || (null_message_ok))) {
+ /* if it is neither a connection_test nor null_message_ok it
+ must be the end of the test */
+ times_up = 1; /* ostensibly the signal handler did this */
+ break;
+ }
+ local_receive_calls += temp_recvs;
+ }
+ else if (rret == -1) {
+ /* test timed-out */
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else if (rret == -2) {
+ /* we timed-out on a data receive. this is only allowed for
+ a UDP_RR test. we want to set things up so we start
+ ramping up again like we were at the beginning. if we
+ actually timeout it means that all has been lost. or at
+ least we assume so */
+ if (debug) {
+ fprintf(where,"Timeout receiving resonse from remote\n");
+ fflush(where);
+ }
+#ifdef WANT_FIRST_BURST
+ if (first_burst_size) {
+ requests_outstanding = 0;
+ }
+#endif
+ if (keep_histogram) {
+ HIST_purge(time_hist);
+ }
+#ifdef WANT_DEMO
+ /* "start over" on a demo interval. we will forget about
+ everything that happened in the demo interval up to the
+ timeout and begin fresh. */
+ demo_reset();
+#endif /* WANT_DEMO */
+
+ continue;
+ }
+ else {
+ /* anything else is bad */
+ perror("netperf: send_omni: recv_data failed");
+ exit(1);
+ }
+ recv_ring = recv_ring->next;
+
+#ifdef WANT_FIRST_BURST
+ /* so, since we've gotten a response back, update the
+ bookkeeping accordingly. there is one less request
+ outstanding and we can put one more out there than
+ before. */
+ requests_outstanding -= 1;
+#endif
+
+ }
+
+ /* if this is a connection test, we want to do some stuff about
+ connection close here in the test loop. raj 2008-01-08 */
+ if (connection_test) {
+
+#ifdef __linux
+ /* so, "Linux" with autotuning likes to alter the socket buffer
+ sizes over the life of the connection, but only does so when
+ one takes the defaults at time of socket creation. if we
+ took those defaults, we should inquire as to what the values
+ ultimately became. raj 2008-01-15 */
+ /* however annoying having to do this might be, it really
+ shouldn't be done over and over again. instead we will
+ assume it does not change, which is fine since we would
+ have only reported one of them anyway. raj 20100917 */
+ if ((lsr_size_req < 0) && (-1 == lsr_size_end))
+ get_sock_buffer(data_socket, RECV_BUFFER, &lsr_size_end);
+ else
+ lsr_size_end = lsr_size;
+ if ((lss_size_req < 0) && (-1 == lss_size_end))
+ get_sock_buffer(data_socket, SEND_BUFFER, &lss_size_end);
+ else
+ lss_size_end = lss_size;
+#else
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+#endif
+
+ /* we will only make this call the one time - after the first
+ call, the value will be real or -1. if this is a connection
+ test we want to do this here because later we won't be
+ connected and the data may no longer be available. */
+ if (transport_mss == -2)
+ get_transport_info(data_socket,
+ &transport_mss,
+ local_res->ai_protocol);
+
+
+ ret = disconnect_data_socket(data_socket,
+ (no_control) ? 1 : 0,
+ 1,
+ NULL,
+ 0);
+ if (ret == 0) {
+ /* we will need a new connection to be established next time
+ around the loop. However, the next time around the loop
+ will already be picking the next port number */
+ need_to_connect = 1;
+ connected = 0;
+ need_socket = 1;
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else {
+ perror("netperf: send_omni: disconnect_data_socket failed");
+ exit(1);
+ }
+ }
+
+
+ if (keep_histogram) {
+ HIST_timestamp_stop_add(time_hist);
+ }
+
+#ifdef WANT_DEMO
+ if (NETPERF_IS_RR(direction)) {
+ if (libfmt == 'x') {
+ demo_interval_tick(1);
+ }
+ else {
+ demo_interval_tick(req_size + rsp_size);
+ }
+ }
+ else if (NETPERF_XMIT_ONLY(direction)) {
+ demo_interval_tick(bytes_to_send);
+ }
+ else {
+ demo_interval_tick(rret);
+ }
+#endif
+
+#if defined(WANT_INTERVALS)
+ INTERVALS_WAIT();
+#endif /* WANT_INTERVALS */
+
+
+ /* was this a "transaction" test? */
+ if (NETPERF_IS_RR(direction)) {
+ trans_completed++;
+ if (units_remaining) {
+ units_remaining--;
+ }
+ }
+
+
+ }
+
+ /* we are now, ostensibly, at the end of this iteration */
+
+#if defined(WANT_DEMO)
+ /* if we were in demo mode this will ensure one final interim
+ result, which, naturally might be a bit early :) */
+ demo_interval_final();
+#endif
+
+ if (transport_mss == -2)
+ get_transport_info(data_socket,
+ &transport_mss,
+ local_res->ai_protocol);
+ local_transport_retrans = get_transport_retrans(data_socket,
+ local_res->ai_protocol);
+
+
+ /* so, if we have/had a data connection, we will want to close it
+ now, and this will be independent of whether there is a control
+ connection. */
+
+ if (connected) {
+
+#ifdef __linux
+ /* so, "Linux" with autotuning likes to alter the socket buffer
+ sizes over the life of the connection, but only does so when
+ one takes the defaults at time of socket creation. if we took
+ those defaults, we should inquire as to what the values
+ ultimately became. raj 2008-01-15 */
+ if (lsr_size_req < 0)
+ get_sock_buffer(data_socket, RECV_BUFFER, &lsr_size_end);
+ else
+ lsr_size_end = lsr_size;
+ if (lss_size_req < 0)
+ get_sock_buffer(data_socket, SEND_BUFFER, &lss_size_end);
+ else
+ lss_size_end = lss_size;
+#else
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+#endif
+ if ((desired_output_groups & OMNI_WANT_LOC_CONG) &&
+ (local_cong_control[0] == '\0')) {
+ get_transport_cong_control(data_socket,
+ local_res->ai_protocol,
+ local_cong_control,
+ sizeof(local_cong_control));
+ }
+
+ /* CHECK PARMS HERE; */
+ ret = disconnect_data_socket(data_socket,
+ 1,
+ 1,
+ NULL,
+ 0);
+ connected = 0;
+ need_socket = 1;
+
+ }
+ else {
+ /* this is the UDP case at present */
+ ret = disconnect_data_socket(data_socket,
+ 1,
+ 1,
+ remote_res->ai_addr,
+ remote_res->ai_addrlen);
+ need_socket = 1;
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+ }
+
+ /* this call will always give us the elapsed time for the test, and
+ will also store-away the necessaries for cpu utilization */
+
+ cpu_stop(local_cpu_usage,&elapsed_time);
+
+ /* if we timed-out, and had padded the timer, we need to subtract
+ the pad_time from the elapsed time on the assumption that we
+ were essentially idle for pad_time and just waiting for a timer
+ to expire on something like a UDP test. if we have not padded
+ the timer, pad_time will be zero. if we have not timed out
+ then we want to make sure we stop the timer. */
+ if (timed_out) {
+ if (debug) {
+ fprintf(where,"Adjusting elapsed_time by %d seconds\n",pad_time);
+ fflush(where);
+ }
+ elapsed_time -= (float)pad_time;
+ }
+ else {
+ stop_timer();
+ }
+
+ if (!no_control) {
+ /* Get the statistics from the remote end. The remote will have
+ calculated service demand and all those interesting things. If
+ it wasn't supposed to care, it will return obvious values. */
+
+ recv_response_n(OMNI_RESULTS_CONV_CUTOFF);
+ if (!netperf_response.content.serv_errno) {
+ if (debug)
+ fprintf(where,"remote results obtained\n");
+ remote_cpu_method = format_cpu_method(omni_result->cpu_method);
+ lib_num_rem_cpus = omni_result->num_cpus;
+ lib_remote_cpu_stats.cpu_util = omni_result->cpu_util;
+ lib_remote_cpu_stats.cpu_user = omni_result->cpu_percent_user;
+ lib_remote_cpu_stats.cpu_system = omni_result->cpu_percent_system;
+ lib_remote_cpu_stats.cpu_iowait = omni_result->cpu_percent_iowait;
+ lib_remote_cpu_stats.cpu_irq = omni_result->cpu_percent_irq;
+ lib_remote_cpu_stats.cpu_swintr = omni_result->cpu_percent_swintr;
+ lib_remote_cpu_stats.peak_cpu_util = omni_result->peak_cpu_util;
+ lib_remote_cpu_stats.peak_cpu_id = omni_result->peak_cpu_id;
+ /* why? because some stacks want to be clever and autotune their
+ socket buffer sizes, which means that if we accept the defaults,
+ the size we get from getsockopt() at the beginning of a
+ connection may not be what we would get at the end of the
+ connection... */
+ rsr_size_end = omni_result->recv_buf_size;
+ rss_size_end = omni_result->send_buf_size;
+ remote_bytes_sent = (uint64_t)omni_result->bytes_sent_hi << 32;
+ remote_bytes_sent += omni_result->bytes_sent_lo;
+ remote_send_calls = omni_result->send_calls;
+ remote_bytes_received = (uint64_t)omni_result->bytes_received_hi << 32;
+ remote_bytes_received += omni_result->bytes_received_lo;
+ remote_receive_calls = omni_result->recv_calls;
+ remote_bytes_xferd = (double) remote_bytes_received +
+ remote_bytes_sent;
+ if (omni_result->recv_calls > 0)
+ remote_bytes_per_recv = (double) remote_bytes_received /
+ (double) omni_result->recv_calls;
+ else
+ remote_bytes_per_recv = 0.0;
+ if (omni_result->send_calls > 0)
+ remote_bytes_per_send = (double) remote_bytes_sent /
+ (double) omni_result->send_calls;
+ else
+ remote_bytes_per_send = 0.0;
+
+ remote_transport_retrans = omni_result->transport_retrans;
+ /* what was the congestion control? */
+ if (desired_output_groups & OMNI_WANT_REM_CONG) {
+ strncpy(remote_cong_control,
+ omni_result->cong_control,
+ sizeof(remote_cong_control));
+ remote_cong_control[sizeof(remote_cong_control) - 1] = '\0';
+ }
+ }
+ else {
+ Set_errno(netperf_response.content.serv_errno);
+ fprintf(where,
+ "netperf: remote error %d",
+ netperf_response.content.serv_errno);
+ perror("");
+ fflush(where);
+
+ exit(-1);
+ }
+ }
+ else {
+ /* when we are sending, in a no_control test, we have to
+ ass-u-me that everything we sent was received, otherwise, we
+ will report a transfer rate of zero. */
+ remote_bytes_xferd = (double) bytes_sent;
+ }
+
+ /* so, what was the end result? */
+ local_cpu_method = format_cpu_method(cpu_method);
+
+ if (local_send_calls > 0)
+ bytes_per_send = (double) bytes_sent / (double) local_send_calls;
+ else bytes_per_send = 0.0;
+
+ if (local_receive_calls > 0)
+ bytes_per_recv = (double) bytes_received / (double) local_receive_calls;
+ else
+ bytes_per_recv = 0.0;
+
+ bytes_xferd = (double) bytes_sent + bytes_received;
+
+ /* if the output format is 'x' we know the test was
+ request/response. if the libfmt is something else, it could be
+ xmit, recv or bidirectional. if we were the receiver then we
+ can use our byte totals even if it is
+ UDP/unreliable. otherwise, we use the remote totals - they
+ should be the same if the protocol is reliable, and if it is
+ unreliable then we want what was actually received */
+ if ('x' == libfmt)
+ /* it was a request/response test */
+ thruput = calc_thruput((double)trans_completed);
+ else if (NETPERF_RECV_ONLY(direction))
+ thruput = calc_thruput(bytes_xferd);
+ else
+ thruput = calc_thruput(remote_bytes_xferd);
+
+ if (NETPERF_IS_RR(direction)) {
+ float rtt_elapsed_time = elapsed_time;
+
+#ifdef WANT_INTERVALS
+ /* if the test was paced, we need to subtract the time we were
+ sitting paced from the time we use to calculate the average
+ rtt_latency. Of course, won't really know how long we were
+ sitting unless we bracket the sit with timing calls, which
+ will be additional overhead affecting CPU utilization. but,
+ there is no such thing as a free lunch is there :) raj
+ 20110121 */
+ if (interval_burst) {
+ rtt_elapsed_time -= (float)(interval_wait_microseconds / 1000000.0);
+ }
+#endif /* WANT_INTERVALS */
+
+ if (!connection_test) {
+ /* calculate the round trip latency, using the transaction rate
+ whether or not the user was asking for thruput to be in 'x'
+ units please... however... a connection_test only ever has
+ one transaction in flight at one time */
+ rtt_latency =
+ (((double)1.0/(trans_completed/rtt_elapsed_time)) *
+ (double)1000000.0) *
+ (double) (1 + ((first_burst_size > 0) ? first_burst_size : 0));
+ }
+ else {
+ rtt_latency = ((double)1.0/(trans_completed/rtt_elapsed_time)) *
+ (double)1000000.0;
+ }
+ tmpfmt = libfmt;
+ libfmt = 'x';
+ transaction_rate = calc_thruput((double)trans_completed);
+ libfmt = tmpfmt;
+ }
+
+ /* ok, time to possibly calculate cpu util and/or service demand */
+ if (local_cpu_usage) {
+
+ local_cpu_utilization = calc_cpu_util(elapsed_time);
+
+ /* we need to decide what to feed the service demand beast,
+ which will, ultimately, depend on what sort of test it is and
+ whether or not the user asked for something specific - as in
+ per KB even on a TCP_RR test if it is being (ab)used as a
+ bidirectional bulk-transfer test. raj 2008-01-14 */
+ local_service_demand =
+ calc_service_demand_fmt(('x' == libfmt) ? (double)trans_completed: bytes_xferd,
+ 0.0,
+ 0.0,
+ 0);
+ }
+ else {
+ local_cpu_utilization = (float) -1.0;
+ local_service_demand = (float) -1.0;
+ }
+
+ if (remote_cpu_usage) {
+
+ remote_cpu_utilization = omni_result->cpu_util;
+
+ remote_service_demand =
+ calc_service_demand_fmt(('x' == libfmt) ? (double) trans_completed: bytes_xferd,
+ 0.0,
+ remote_cpu_utilization,
+ omni_result->num_cpus);
+ }
+ else {
+ remote_cpu_utilization = (float) -1.0;
+ remote_service_demand = (float) -1.0;
+ }
+
+ /* time to calculate our confidence */
+ calculate_confidence(confidence_iteration,
+ elapsed_time,
+ thruput,
+ local_cpu_utilization,
+ remote_cpu_utilization,
+ local_service_demand,
+ remote_service_demand);
+
+ /* this this is the end of the confidence while loop? */
+ confidence_iteration++;
+ }
+
+ /* we end with confidence_iteration one larger than the number of
+ iterations. if we weren't doing confidence intervals this will
+ still be reported as one */
+ confidence_iteration--;
+
+#if defined(WANT_INTERVALS)
+#ifdef WIN32
+ stop_itimer();
+#endif
+#endif /* WANT_INTERVALS */
+
+/* at some point we may want to actually display some results :) */
+
+ retrieve_confident_values(&elapsed_time,
+ &thruput,
+ &local_cpu_utilization,
+ &remote_cpu_utilization,
+ &local_service_demand,
+ &remote_service_demand);
+
+ /* a kludge for omni printing because I don't know how to tell that
+ something is a float vs a double in my_snprintf() given what it
+ is passed and I'm not ready to force all the netlib.c stuff to
+ use doubles rather than floats. help there would be
+ appreciated. raj 2008-01-28 */
+ elapsed_time_double = (double) elapsed_time;
+ local_service_demand_double = (double)local_service_demand;
+ remote_service_demand_double = (double)remote_service_demand;
+
+ if ('x' == libfmt) sd_str = "usec/Tran";
+ else sd_str = "usec/KB";
+
+ if (iteration_max > 1) {
+ result_confid_pct = get_result_confid();
+ loc_cpu_confid_pct = get_loc_cpu_confid();
+ rem_cpu_confid_pct = get_rem_cpu_confid();
+ interval_pct = interval * 100.0;
+ }
+
+ /* at some point we need to average these during a confidence
+ interval run, and when we do do that, we need to make sure we
+ restore the value of libfmt correctly */
+ tmpfmt = libfmt;
+ if ('x' == libfmt) {
+ libfmt = 'm';
+ }
+ local_send_thruput = calc_thruput((double)bytes_sent);
+ local_recv_thruput = calc_thruput((double)bytes_received);
+ remote_send_thruput = calc_thruput((double)remote_bytes_sent);
+ remote_recv_thruput = calc_thruput((double)remote_bytes_received);
+
+ libfmt = tmpfmt;
+
+ /* were we tracking possibly expensive statistics? */
+ if (keep_statistics) {
+ HIST_get_stats(time_hist,
+ &min_latency,
+ &max_latency,
+ &mean_latency,
+ &stddev_latency);
+ p50_latency = HIST_get_percentile(time_hist, 0.50);
+ p90_latency = HIST_get_percentile(time_hist, 0.90);
+ p99_latency = HIST_get_percentile(time_hist, 0.99);
+
+ }
+
+ /* if we are running a legacy test we do not do the nifty new omni
+ output stuff */
+ if (!legacy) {
+ print_omni();
+ }
+
+#if defined(DEBUG_OMNI_OUTPUT)
+ {
+ /* just something quick to sanity check the output selectors. this
+ should be gone for "production" :) */
+ int i;
+ print_omni_init();
+ output_list[0][1] = OUTPUT_END;
+ for (i = OUTPUT_NONE; i < NETPERF_OUTPUT_MAX; i++) {
+ output_list[0][0] = i;
+ print_omni_csv();
+ }
+ }
+#endif
+
+ /* likely as not we are going to do something slightly different here */
+ if ((verbosity > 1) && (!legacy)) {
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\nHistogram of ");
+ if (NETPERF_RECV_ONLY(direction))
+ fprintf(where,"recv");
+ if (NETPERF_XMIT_ONLY(direction))
+ fprintf(where,"send");
+ if (NETPERF_IS_RR(direction)) {
+ if (connection_test) {
+ if (NETPERF_CC(direction)) {
+ fprintf(where,"connect/close");
+ }
+ else {
+ fprintf(where,"connect/request/response/close");
+ }
+ }
+ else {
+ fprintf(where,"request/response");
+ }
+ }
+ fprintf(where," times\n");
+ HIST_report(time_hist);
+ fflush(where);
+#endif /* WANT_HISTOGRAM */
+
+ }
+
+}
+
+
+void
+send_omni(char remote_host[])
+{
+ char name_buf[32];
+ snprintf(name_buf,sizeof(name_buf),"OMNI %s TEST",direction_str);
+ name_buf[31] = '\0';
+ send_omni_inner(remote_host, 0, name_buf);
+}
+
+#if defined(WIN32)
+#if !defined(InetNtop)
+/* +*+ Why isn't this in the winsock headers yet? */
+const char *
+inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+#endif
+
+static void
+set_hostname_and_port_2(void *addr, char *hostname, char *portstr, int family, int port)
+{
+
+ inet_ntop(family, addr, hostname, BUFSIZ);
+
+ sprintf(portstr, "%u", port);
+
+}
+
+
+
+/* the name is something of a misnomer since this test could send, or
+ receive, or both, but it matches the historical netperf routine
+ naming convention for what runs in the netserver context. */
+void
+recv_omni()
+{
+
+ struct addrinfo *local_res;
+ char local_name[BUFSIZ];
+ char port_buffer[PORTBUFSIZE];
+
+ struct sockaddr_storage myaddr_in, peeraddr_in;
+ int peeraddr_set = 0;
+ SOCKET s_listen, data_socket;
+ netperf_socklen_t addrlen;
+
+ struct ring_elt *send_ring;
+ struct ring_elt *recv_ring;
+
+ int timed_out = 0;
+ int pad_time = 0;
+ int need_to_connect = 0;
+ int need_to_accept;
+ int connected;
+ int ret;
+ uint32_t temp_recvs;
+
+ struct omni_request_struct *omni_request;
+ struct omni_response_struct *omni_response;
+ struct omni_results_struct *omni_results;
+
+ omni_request =
+ (struct omni_request_struct *)netperf_request.content.test_specific_data;
+ omni_response =
+ (struct omni_response_struct *)netperf_response.content.test_specific_data;
+ omni_results =
+ (struct omni_results_struct *)netperf_response.content.test_specific_data;
+
+ if (debug) {
+ fprintf(where,"netserver: %s: entered...\n",__FUNCTION__);
+ fflush(where);
+ }
+
+ /* netserver has no good way of knowing where the conversion cutoff
+ point is, so we have to fix it after the fact */
+ fixup_request_n(OMNI_REQUEST_CONV_CUTOFF);
+
+ /* thus fixed-up, we can extract the requested congestion control
+ algorithm */
+ strncpy(local_cong_control_req,
+ omni_request->cong_control,
+ sizeof(local_cong_control_req));
+
+ /* based on what we have been told by the remote netperf, we want to
+ setup our endpoint for the "data connection" and let the remote
+ netperf know the situation. */
+
+ if (debug) {
+ fprintf(where,"%s: setting the response type...\n",__FUNCTION__);
+ fflush(where);
+ }
+
+ netperf_response.content.response_type = OMNI_RESPONSE;
+
+ if (debug) {
+ fprintf(where,"%s: the response type is set...\n",__FUNCTION__);
+ fflush(where);
+ }
+
+ /* Grab a socket to listen on, and then listen on it. */
+
+ if (debug) {
+ fprintf(where,"%s: grabbing a socket...\n",__FUNCTION__);
+ fflush(where);
+ }
+
+ /* create_data_socket expects to find some things in the global
+ variables, so set the globals based on the values in the request.
+ once the socket has been created, we will set the response values
+ based on the updated value of those globals. raj 7/94 */
+ lss_size_req = omni_request->send_buf_size;
+ lsr_size_req = omni_request->recv_buf_size;
+ loc_nodelay = (omni_request->flags) & OMNI_NO_DELAY;
+ loc_rcvavoid = omni_request->so_rcvavoid;
+ loc_sndavoid = omni_request->so_sndavoid;
+ routing_allowed = (omni_request->flags) & OMNI_ROUTING_ALLOWED;
+ want_keepalive = (omni_request->flags) & OMNI_WANT_KEEPALIVE;
+ local_socket_prio = omni_request->socket_prio;
+ local_socket_tos = omni_request->socket_tos;
+ want_defer_accept = omni_request->flags & OMNI_WANT_DEFER_ACCEPT;
+
+#ifdef WANT_INTERVALS
+ interval_usecs = omni_request->interval_usecs;
+ interval_wate = interval_usecs / 1000;
+ interval_burst = omni_request->interval_burst;
+#else
+ interval_usecs = 0;
+ interval_wate = 1;
+ interval_burst = 0;
+#endif
+
+ connection_test = omni_request->flags & OMNI_CONNECT_TEST;
+#ifdef TCP_FASTOPEN
+ use_fastopen = omni_request->flags & OMNI_FASTOPEN;
+#endif
+ direction = omni_request->direction;
+ use_pktinfo = (omni_request->flags) & OMNI_USE_PKTINFO;
+
+ /* let's be quite certain the fill file string is null terminated */
+ omni_request->fill_file[sizeof(omni_request->fill_file) - 1] = '\0';
+ strncpy(local_fill_file,
+ omni_request->fill_file,
+ sizeof(local_fill_file));
+
+ /* kludgy, because I have no way at present to say how many bytes
+ needed to be swapped around for the request from which this is
+ pulled, and it is probably all wrong for IPv6 :( */
+ switch (nf_to_af(omni_request->ipfamily)) {
+ case AF_INET6:
+ /* yes indeed it is, do nothing, bz */
+ break;
+ case AF_INET:
+ default:
+ for (ret=0; ret < 4; ret++) {
+ omni_request->netserver_ip[ret] = htonl(omni_request->netserver_ip[ret]);
+ omni_request->netperf_ip[ret] = htonl(omni_request->netperf_ip[ret]);
+ }
+ break;
+ }
+
+ set_hostname_and_port_2(omni_request->netserver_ip,
+ local_name,
+ port_buffer,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->data_port);
+
+ local_res = complete_addrinfo(local_name,
+ local_name,
+ port_buffer,
+ nf_to_af(omni_request->ipfamily),
+ nst_to_hst(omni_request->socket_type),
+ omni_request->protocol,
+ 0);
+
+ s_listen = omni_create_data_socket(local_res);
+
+ if (s_listen == INVALID_SOCKET) {
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ if (debug) {
+ fprintf(where,"could not create data socket\n");
+ fflush(where);
+ }
+ exit(-1);
+ }
+
+ /* We now alter the message_ptr variables to be at the desired */
+ /* alignments with the desired offsets. */
+
+ if (debug) {
+ fprintf(where,
+ "recv_omni: requested recv alignment of %d offset %d\n"
+ "recv_omni: requested send alignment of %d offset %d\n",
+ omni_request->recv_alignment,
+ omni_request->recv_offset,
+ omni_request->send_alignment,
+ omni_request->send_offset);
+ fflush(where);
+ }
+
+ omni_response->send_size = omni_request->send_size;
+ omni_response->send_width = omni_request->send_width;
+ omni_response->socket_prio = local_socket_prio;
+ omni_response->socket_tos = local_socket_tos;
+
+ if (omni_request->direction & NETPERF_XMIT) {
+#ifdef fo
+ /* do we need to set multicast ttl? */
+ if (is_multicast_addr(remote_res)) {
+ /* yes, s_listen - for a UDP test we will be copying it to
+ data_socket but that hasn't happened yet. raj 20100315 */
+ set_multicast_ttl(s_listen);
+ }
+#endif
+
+ if (omni_request->response_size > 0) {
+ /* request/response_test */
+ bytes_to_send = omni_request->response_size;
+ if (omni_request->send_width == 0) send_width = 1;
+ else send_width = omni_request->send_width;
+ }
+ else {
+ if (omni_request->send_size == -1) {
+ bytes_to_send = choose_send_size(lss_size,omni_request->protocol);
+ }
+ else bytes_to_send = omni_request->send_size;
+ /* set the send_width */
+ if (omni_request->send_width == 0) {
+ send_width = (lss_size/bytes_to_send) + 1;
+ if (send_width == 1) send_width++;
+ }
+ else
+ send_width = omni_request->send_width;
+ }
+ send_ring = allocate_buffer_ring(send_width,
+ bytes_to_send,
+ omni_request->send_alignment,
+ omni_request->send_offset);
+
+ omni_response->send_width = send_width;
+ omni_response->send_size = bytes_to_send;
+ }
+
+ omni_response->receive_size = omni_request->receive_size;
+ omni_response->recv_width = omni_request->recv_width;
+ if (omni_request->direction & NETPERF_RECV) {
+
+ /* do we need to join a multicast group? */
+ if (is_multicast_addr(local_res)) {
+ /* yes, s_listen - for a UDP test we will be copying it to
+ data_socket but that hasn't happened yet. raj 20100315 */
+ join_multicast_addr(s_listen, local_res);
+ }
+
+ if (omni_request->request_size > 0) {
+ /* request/response test */
+ bytes_to_recv = omni_request->request_size;
+ if (omni_request->recv_width == 0) recv_width = 1;
+ else recv_width = omni_request->recv_width;
+ }
+ else {
+ if (omni_request->receive_size == -1) {
+ if (lsr_size > 0) bytes_to_recv = lsr_size;
+ else bytes_to_recv = 4096;
+ }
+ else {
+ bytes_to_recv = omni_request->receive_size;
+ }
+ /* set the recv_width */
+ if (omni_request->recv_width == 0) {
+ recv_width = (lsr_size/bytes_to_recv) + 1;
+ if (recv_width == 1) recv_width++;
+ }
+ else
+ recv_width = omni_request->recv_width;
+ }
+ recv_ring = allocate_buffer_ring(recv_width,
+ bytes_to_recv,
+ omni_request->recv_alignment,
+ omni_request->recv_offset);
+
+ omni_response->receive_size = bytes_to_recv;
+ omni_response->recv_width = recv_width;
+ }
+
+#ifdef WIN32
+ /* The test timer can fire during operations on the listening socket,
+ so to make the start_timer below work we have to move
+ it to close s_listen while we are blocked on accept. */
+ win_kludge_socket2 = s_listen;
+#endif
+
+ need_to_accept = (omni_request->protocol != IPPROTO_UDP);
+
+ /* we need to hang a listen for everything that needs at least one
+ accept. the age-old constant of 5 is probably OK for our purposes
+ but does not necessarily represent best practice */
+ if (need_to_accept) {
+ int backlog = 5;
+#ifdef TCP_FASTOPEN
+ /* one of these days I will have to go find-out what the backlog
+ is supposed to be here. until then, I'll just set it to five
+ like the listen() call does - it is classic, and was what was
+ used in the online example I found */
+ if (use_fastopen &&
+ (setsockopt(s_listen,IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog)) ==
+ SOCKET_ERROR)) {
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,"netperfserver: %s could not fastopen\n",__FUNCTION__);
+ fflush(where);
+ }
+ exit(1);
+ }
+#endif /* TCP_FASTOPEN */
+#ifdef TCP_DEFER_ACCEPT
+ if (want_defer_accept &&
+ (setsockopt(s_listen, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(backlog)) == SOCKET_ERROR)) {
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,
+ "netperfserver: %s could not defer accept\n",__FUNCTION__);
+ fflush(where);
+ }
+ exit(1);
+ }
+#endif /* TCP_DEFER_ACCEPT */
+ if (listen(s_listen, backlog) == SOCKET_ERROR) {
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,"netperfserver: %s could not listen\n",__FUNCTION__);
+ fflush(where);
+ }
+ exit(1);
+ }
+ }
+
+ /* now get the port number assigned by the system */
+ addrlen = sizeof(myaddr_in);
+ if (getsockname(s_listen,
+ (struct sockaddr *)&myaddr_in,
+ &addrlen) == SOCKET_ERROR){
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,"could not getsockname\n");
+ fflush(where);
+ }
+ exit(-1);
+ }
+
+ /* Now myaddr_in contains the port and the internet address this is
+ returned to the sender also implicitly telling the sender that
+ the socket buffer sizing has been done. likely as not, the IP
+ address will be the wildcard - so we only really need to extract
+ the port number. since send_response is going to call htonl on
+ all the fields, we want to initially put the port number in there
+ in host order. */
+
+ omni_response->data_port =
+ (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
+ if (debug) {
+ fprintf(where,"telling the remote to call me at %d\n",
+ omni_response->data_port);
+ fflush(where);
+ }
+ netperf_response.content.serv_errno = 0;
+
+ /* But wait, there's more. If the initiator wanted cpu measurements, */
+ /* then we must call the calibrate routine, which will return the max */
+ /* rate back to the initiator. If the CPU was not to be measured, or */
+ /* something went wrong with the calibration, we will return a 0.0 to */
+ /* the initiator. */
+
+ omni_response->cpu_rate = (float)0.0; /* assume no cpu */
+ omni_response->flags &= ~OMNI_MEASURE_CPU;
+ if (omni_request->flags & OMNI_MEASURE_CPU) {
+ omni_response->flags |= OMNI_MEASURE_CPU;
+ omni_response->cpu_rate =
+ calibrate_local_cpu(omni_request->cpu_rate);
+ }
+
+ /* before we send the response back to the initiator, pull some of */
+ /* the socket parms from the globals */
+ omni_response->send_buf_size = lss_size;
+ omni_response->recv_buf_size = lsr_size;
+ if (loc_nodelay)
+ omni_response->flags |= OMNI_NO_DELAY;
+ else
+ omni_response->flags &= ~OMNI_NO_DELAY;
+
+ omni_response->so_rcvavoid = loc_rcvavoid;
+ omni_response->so_sndavoid = loc_sndavoid;
+ omni_response->interval_usecs = interval_usecs;
+ omni_response->interval_burst = interval_burst;
+
+ send_response_n(OMNI_RESPONSE_CONV_CUTOFF); /* brittle, but functional */
+
+ local_send_calls = 0;
+ local_receive_calls = 0;
+
+ addrlen = sizeof(peeraddr_in);
+ memset(&peeraddr_in,0,sizeof(peeraddr_in));
+
+ /* Now it's time to start receiving data on the connection. We will */
+ /* first grab the apropriate counters and then start grabbing. */
+
+ cpu_start(omni_request->flags & OMNI_MEASURE_CPU);
+
+ /* if the test is timed, set a timer of suitable length. if the
+ test is by byte/transaction count, we don't need a timer - or
+ rather we rely on the netperf to only ask us to do transaction
+ counts over "reliable" protocols. perhaps at some point we
+ should add a check herebouts to verify that... */
+
+ if (omni_request->test_length >= 0) {
+ times_up = 0;
+ units_remaining = 0;
+ test_time=omni_request->test_length;
+ /* if we are the sender and only sending, then we don't need/want
+ the padding, otherwise, we need the padding */
+ if (!(NETPERF_XMIT_ONLY(omni_request->direction)) &&
+ (omni_request->test_length > 0))
+ pad_time = PAD_TIME;
+ start_timer(omni_request->test_length + pad_time);
+ }
+ else {
+ times_up = 1;
+ units_remaining = omni_request->test_length * -1;
+ }
+
+#if defined(WANT_INTERVALS)
+ INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+
+ trans_completed = 0;
+ bytes_sent = 0;
+ bytes_received = 0;
+ connected = 0;
+
+ while ((!times_up) || (units_remaining > 0)) {
+
+ if (need_to_accept) {
+ /* accept a connection from the remote */
+#ifdef WIN32
+ /* The test timer will probably fire during this accept,
+ so to make the start_timer above work we have to move
+ it to close s_listen while we are blocked on accept. */
+ win_kludge_socket = s_listen;
+#endif
+ if ((data_socket=accept(s_listen,
+ (struct sockaddr *)&peeraddr_in,
+ &addrlen)) == INVALID_SOCKET) {
+ if (errno == EINTR) {
+ /* the timer popped */
+ times_up = 1; /* ostensibly the signal hander dealt with this?*/
+ timed_out = 1;
+ break;
+ }
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ fprintf(where,"%s: accept: errno = %d\n",__FUNCTION__,errno);
+ fflush(where);
+ close(s_listen);
+
+ exit(-1);
+ }
+
+ if (debug) {
+ fprintf(where,"%s: accepted data connection.\n",__FUNCTION__);
+ fflush(where);
+ }
+ need_to_accept = 0;
+ connected = 1;
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+ /* this is for those systems which *INCORRECTLY* fail to pass
+ attributes across an accept() call. Including this goes
+ against my better judgement :( raj 11/95 */
+
+ kludge_socket_options(data_socket);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+ }
+ else {
+ /* I wonder if duping would be better here? we also need to set
+ peeraddr_in so we can send to netperf if this isn't a
+ request/response test or if we are going to connect() the
+ socket, but we only need to do it once. */
+ if ((omni_request->protocol == IPPROTO_UDP) &&
+ (!peeraddr_set)) {
+ peeraddr_set = 1;
+ data_socket = s_listen;
+ set_sockaddr_family_addr_port(&peeraddr_in,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->netperf_ip,
+ omni_request->netperf_port);
+ }
+ }
+
+#ifdef WIN32
+ /* this is used so the timer thread can close the socket out from
+ under us, which to date is the easiest/cleanest/least
+ Windows-specific way I can find to force the winsock calls to
+ return WSAEINTR with the test is over. anything that will run on
+ 95 and NT and is closer to what netperf expects from Unix signals
+ and such would be appreciated raj 1/96 */
+ win_kludge_socket = data_socket;
+#endif /* WIN32 */
+
+ /* in recv_omni, we check recv first, and _then_ send, otherwise,
+ a request/response test will be all messed-up :) and that then
+ is why there are two routines to rule them all rather than just
+ one :) */
+ if ((omni_request->direction & NETPERF_RECV) &&
+ ((!times_up) || (units_remaining > 0))) {
+ ret = recv_data(data_socket,
+ recv_ring,
+ bytes_to_recv,
+ (connected) ? NULL : (struct sockaddr *)&peeraddr_in,
+ &addrlen,
+ /* if XMIT also, then this is RR test so waitall */
+ (direction & NETPERF_XMIT) ? NETPERF_WAITALL: 0,
+ &temp_recvs);
+ if (ret > 0) {
+ /* if this is a recv-only test controlled by byte count we
+ decrement the units_remaining by the bytes received */
+ if (!(direction & NETPERF_XMIT) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_received += ret;
+ local_receive_calls += temp_recvs;
+ }
+ else if (ret == 0) {
+ /* is this the end of a test, just a zero-byte recv, or
+ something else? that is an exceedingly good question and
+ one for which I don't presently have a good answer, but
+ that won't stop me from guessing :) raj 2008-01-09 */
+ if (!((connection_test) || (null_message_ok))) {
+ /* if it is neither a connection_test nor null_message_ok it
+ must be the end of the test */
+ times_up = 1;
+ break;
+ }
+ local_receive_calls += temp_recvs;
+ }
+ else if (ret == -1) {
+ /* test timed-out */
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else {
+ /* presently at least, -2 and -3 are equally bad on recv */
+ /* we need a response message here for the control connection
+ before we exit! */
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ exit(-1);
+ }
+ recv_ring = recv_ring->next;
+ }
+
+ /* if we should try to send something, then by all means, let us
+ try to send something. */
+ if ((omni_request->direction & NETPERF_XMIT) &&
+ ((!times_up) || (units_remaining > 0))) {
+
+ /* there used to be some code here looking sched_yield() until
+ there was no more queued, unsent data on the socket but
+ frankly, I've no idea what that was all about so I have
+ removed it. It may have been part of a kludge to try to avoid
+ coalescing requests and responses */
+
+ if (omni_request->protocol == IPPROTO_UDP && need_to_connect &&
+ !connected) {
+ if (connect(data_socket,
+ (struct sockaddr*)&peeraddr_in,
+ addrlen) == INVALID_SOCKET) {
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ close(data_socket);
+ exit(-1);
+ }
+ connected = 1;
+ }
+
+ ret = send_data(data_socket,
+ send_ring,
+ bytes_to_send,
+ (connected) ? NULL : (struct sockaddr *)&peeraddr_in,
+ addrlen,
+ omni_request->protocol);
+
+ /* the order of these if's will seem a triffle strange, but they
+ are my best guess as to order of probabilty and/or importance
+ to the overhead raj 2008-01-09*/
+ if (ret == bytes_to_send) {
+ /* if this is a send-only test controlled by byte count we
+ decrement units_remaining by the bytes sent */
+ if (!(direction & NETPERF_RECV) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_sent += ret;
+ send_ring = send_ring->next;
+ local_send_calls++;
+ }
+ else if (ret == -2) {
+ /* what to do here -2 means a non-fatal error - probably
+ ENOBUFS and so our send didn't happen. in the old code for
+ UDP_STREAM we would just continue in the while loop. it
+ isn't clear that is what to do here, so we will simply
+ increment the failed_sends stat and fall-through. If this
+ is a UDP_STREAM style of test, the net effect should be the
+ same. if this is a UDP_RR with a really-big burst count, I
+ don't think we were checking for ENOBUFS there anyway and
+ so would have failed. Here we can just let things
+ slide. */
+ failed_sends++;
+ }
+ else if (ret == 0) {
+ /* was this a zero-byte send? if it was, then ostensibly we
+ would hit the ret == bytes_to_send case which means we'd
+ never get here as we are using blocking semantics */
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else {
+ /* we need a response message back to netperf here before we
+ exit */
+ /* NEED RESPONSE; */
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ exit(-1);
+ }
+
+ }
+
+ if (connection_test) {
+#ifdef __linux
+ /* so, "Linux" with autotuning likes to alter the socket buffer
+ sizes over the life of the connection, but only does so when
+ one takes the defaults at time of socket creation. if we
+ took those defaults, we should inquire as to what the values
+ ultimately became. raj 2008-01-15 */
+ /* but as annoying as it is to have to make these calls, don't
+ penalize linux by calling them over and over again. instead
+ we will simply ass-u-me that it will become the same value
+ over and over again. raj 20100917 */
+ if ((lsr_size_req < 0) && (-1 == lsr_size_end))
+ get_sock_buffer(data_socket, RECV_BUFFER, &lsr_size_end);
+ else
+ lsr_size_end = lsr_size;
+ if ((lss_size_req < 0) && (-1 == lss_size_end))
+ get_sock_buffer(data_socket, SEND_BUFFER, &lss_size_end);
+ else
+ lss_size_end = lss_size;
+#else
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+#endif
+ ret = close_data_socket(data_socket,NULL,0,omni_request->protocol);
+ if (ret == -1) {
+ times_up = 1;
+ timed_out = 1;
+ break;
+ }
+ else if (ret < 0) {
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ perror("netperf: recv_omni: close_data_socket failed");
+ fflush(where);
+ exit(-1);
+ }
+ /* we will need a new connection to be established */
+ need_to_accept = 1;
+ connected = 0;
+ }
+
+#if defined(WANT_INTERVALS)
+ INTERVALS_WAIT();
+#endif /* WANT_INTERVALS */
+
+ /* was this a "transaction" test? don't for get that a TCP_CC
+ style test will have no xmit or recv :) so, we check for either
+ both XMIT and RECV set, or neither XMIT nor RECV set */
+ if (NETPERF_IS_RR(omni_request->direction)) {
+ trans_completed++;
+ if (units_remaining) {
+ units_remaining--;
+ }
+ }
+ }
+
+ /* The current iteration loop now exits due to timeout or unit count
+ being reached */
+ stop_timer();
+ cpu_stop(omni_request->flags & OMNI_MEASURE_CPU,&elapsed_time);
+ close(s_listen);
+
+#if defined(WANT_INTERVALS)
+#ifdef WIN32
+ stop_itimer();
+#endif
+#endif /* WANT_INTERVALS */
+
+ if (timed_out) {
+ /* we ended the test by time, which may have been PAD_TIME seconds
+ longer than we wanted to run. so, we want to subtract pad_time
+ from the elapsed_time. if we didn't pad the timer pad_time will
+ be 0 so we can just subtract it anyway :) */
+ if (debug) {
+ fprintf(where,"Adjusting elapsed time by %d seconds\n",pad_time);
+ fflush(where);
+ }
+ elapsed_time -= pad_time;
+ }
+
+ remote_transport_retrans = get_transport_retrans(data_socket,
+ omni_request->protocol);
+
+ if (connected) {
+#ifdef __linux
+ /* so, "Linux" with autotuning likes to alter the socket buffer
+ sizes over the life of the connection, but only does so when
+ one takes the defaults at time of socket creation. if we took
+ those defaults, we should inquire as to what the values
+ ultimately became. raj 2008-01-15 */
+ if (lsr_size_req < 0)
+ get_sock_buffer(data_socket, RECV_BUFFER, &lsr_size_end);
+ else
+ lsr_size_end = lsr_size;
+ if (lss_size_req < 0)
+ get_sock_buffer(data_socket, SEND_BUFFER, &lss_size_end);
+ else
+ lss_size_end = lss_size;
+#else
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+#endif
+ if (omni_request->flags & OMNI_WANT_REM_CONG) {
+ get_transport_cong_control(data_socket,
+ local_res->ai_protocol,
+ omni_results->cong_control,
+ sizeof(omni_results->cong_control));
+ }
+ else {
+ strncpy(omni_results->cong_control,"",sizeof(omni_results->cong_control));
+ }
+
+
+ close_data_socket(data_socket,NULL,0,omni_request->protocol);
+ }
+ else {
+ close_data_socket(data_socket,(struct sockaddr *)&peeraddr_in,addrlen,omni_request->protocol);
+ lsr_size_end = lsr_size;
+ lss_size_end = lss_size;
+ }
+
+ /* send the results to the sender */
+
+ omni_results->send_calls = (uint32_t) local_send_calls;
+ omni_results->bytes_received_lo = bytes_received & 0x00000000FFFFFFFFULL;
+ omni_results->bytes_received_hi = (bytes_received & 0xFFFFFFFF00000000ULL) >> 32;
+ omni_results->recv_buf_size = lsr_size_end;
+ omni_results->recv_calls = (uint32_t) local_receive_calls;
+ omni_results->bytes_sent_lo = bytes_sent & 0x00000000FFFFFFFFULL;
+ omni_results->bytes_sent_hi = (bytes_sent & 0xFFFFFFFF00000000ULL) >> 32;
+ omni_results->send_buf_size = lss_size_end;
+ omni_results->trans_received = (uint32_t) trans_completed;
+ omni_results->elapsed_time = elapsed_time;
+ omni_results->transport_retrans = remote_transport_retrans;
+ omni_results->cpu_method = cpu_method;
+ omni_results->num_cpus = lib_num_loc_cpus;
+ if (omni_request->flags & OMNI_MEASURE_CPU) {
+ omni_results->cpu_util = calc_cpu_util(elapsed_time);
+ omni_results->cpu_percent_user = lib_local_cpu_stats.cpu_user;
+ omni_results->cpu_percent_system = lib_local_cpu_stats.cpu_system;
+ omni_results->cpu_percent_iowait = lib_local_cpu_stats.cpu_iowait;
+ omni_results->cpu_percent_irq = lib_local_cpu_stats.cpu_irq;
+ omni_results->cpu_percent_swintr = lib_local_cpu_stats.cpu_swintr;
+ omni_results->peak_cpu_util = lib_local_cpu_stats.peak_cpu_util;
+ omni_results->peak_cpu_id = lib_local_cpu_stats.peak_cpu_id;
+ }
+
+#if defined(WANT_INTERVALS)
+#ifdef WIN32
+ stop_itimer();
+#endif
+#endif /* WANT_INTERVALS */
+
+ if (debug) {
+ fprintf(where,
+ "%s: test complete, sending results.\n",
+ __FUNCTION__);
+ fflush(where);
+ }
+
+ send_response_n(OMNI_RESULTS_CONV_CUTOFF);
+
+}
+
+
+#ifdef WANT_MIGRATION
+void
+send_tcp_stream(char remote_host[])
+{
+
+ char *tput_title = "\
+Recv Send Send \n\
+Socket Socket Message Elapsed \n\
+Size Size Size Time Throughput \n\
+bytes bytes bytes secs. %s/sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f %s\n";
+
+ char *tput_fmt_1 =
+ "%6d %6d %6d %-6.2f %7.2f %s\n";
+
+ char *cpu_title = "\
+Recv Send Send Utilization Service Demand\n\
+Socket Socket Message Elapsed Send Recv Send Recv\n\
+Size Size Size Time Throughput local remote local remote\n\
+bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f %c %s\n";
+
+ char *cpu_fmt_1 =
+ "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
+
+ char *ksink_fmt = "\n\
+Alignment Offset %-8.8s %-8.8s Sends %-8.8s Recvs\n\
+Local Remote Local Remote Xfered Per Per\n\
+Send Recv Send Recv Send (avg) Recv (avg)\n\
+%5d %5d %5d %5d %6"PRId64" %6.2f %6"PRId64" %6.2f %6"PRId64"\n";
+
+ char *ksink_fmt2 = "\n\
+Maximum\n\
+Segment\n\
+Size (bytes)\n\
+%6d\n";
+
+ send_omni_inner(remote_host, legacy, "MIGRATED TCP STREAM TEST");
+
+
+ if (legacy) {
+
+ /* We are now ready to print all the information, but only if we
+ are truly acting as a legacy test. If the user has specified
+ zero-level verbosity, we will just print the local service
+ demand, or the remote service demand. If the user has requested
+ verbosity level 1, he will get the basic "streamperf"
+ numbers. If the user has specified a verbosity of greater than
+ 1, we will display a veritable plethora of background
+ information from outside of this block as it it not
+ cpu_measurement specific... */
+
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ remote_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ cpu_title,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
+
+ fprintf(where,
+ cpu_fmt_1, /* the format string */
+ rsr_size, /* remote recvbuf size */
+ lss_size, /* local sendbuf size */
+ send_size, /* how large were the sends */
+ elapsed_time, /* how long was the test */
+ thruput, /* what was the xfer rate */
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand, /* remote service demand */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,tput_title,format_units());
+ }
+ fprintf(where,
+ tput_fmt_1, /* the format string */
+ rsr_size, /* remote recvbuf size */
+ lss_size, /* local sendbuf size */
+ send_size, /* how large were the sends */
+ elapsed_time, /* how long did it take */
+ thruput, /* how fast did it go */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* TCP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+ /* this stuff needs to be worked-out in the presence of confidence */
+ /* intervals and multiple iterations of the test... raj 11/94 */
+
+ fprintf(where,
+ ksink_fmt,
+ "Bytes",
+ "Bytes",
+ "Bytes",
+ local_send_align,
+ remote_recv_align,
+ local_send_offset,
+ remote_recv_offset,
+ bytes_sent,
+ bytes_sent / (double)local_send_calls,
+ local_send_calls,
+ bytes_sent / (double)remote_receive_calls,
+ remote_receive_calls);
+ fprintf(where,
+ ksink_fmt2,
+ transport_mss);
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\n\nHistogram of time spent in send() call.\n");
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+ fflush(where);
+ }
+
+ }
+}
+
+void
+send_tcp_maerts(char remote_host[])
+{
+
+ char *tput_title = "\
+Recv Send Send \n\
+Socket Socket Message Elapsed \n\
+Size Size Size Time Throughput \n\
+bytes bytes bytes secs. %s/sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f %s\n";
+
+ char *tput_fmt_1 =
+ "%6d %6d %6d %-6.2f %7.2f %s\n";
+
+ char *cpu_title = "\
+Recv Send Send Utilization Service Demand\n\
+Socket Socket Message Elapsed Recv Send Recv Send\n\
+Size Size Size Time Throughput local remote local remote\n\
+bytes bytes bytes secs. %-8.8s/s %% %c %% %c us/KB us/KB\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f %c %s\n";
+
+ char *cpu_fmt_1 =
+ "%6d %6d %6d %-6.2f %7.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
+
+ char *ksink_fmt = "\n\
+Alignment Offset %-8.8s %-8.8s Recvs %-8.8s Sends\n\
+Local Remote Local Remote Xfered Per Per\n\
+Recv Send Recv Send Recv (avg) Send (avg)\n\
+%5d %5d %5d %5d %6"PRId64" %6.2f %6d %6.2f %6d\n";
+
+ char *ksink_fmt2 = "\n\
+Maximum\n\
+Segment\n\
+Size (bytes)\n\
+%6d\n";
+
+ send_omni_inner(remote_host, legacy, "MIGRATED TCP MAERTS TEST");
+
+
+ /* We are now ready to print all the information, but only if we are
+ truly acting as a leacy test. If the user has specified
+ zero-level verbosity, we will just print the local service
+ demand, or the remote service demand. If the user has requested
+ verbosity level 1, he will get the basic "streamperf" numbers. If
+ the user has specified a verbosity of greater than 1, we will
+ display a veritable plethora of background information from
+ outside of this block as it it not cpu_measurement
+ specific... */
+
+ if (legacy) {
+
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ remote_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ cpu_title,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
+
+ fprintf(where,
+ cpu_fmt_1, /* the format string */
+ rsr_size, /* remote recvbuf size */
+ lss_size, /* local sendbuf size */
+ remote_send_size, /* how large were the recvs */
+ elapsed_time, /* how long was the test */
+ thruput, /* what was the xfer rate */
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand, /* remote service demand */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,tput_title,format_units());
+ }
+ fprintf(where,
+ tput_fmt_1, /* the format string */
+ lsr_size, /* local recvbuf size */
+ rss_size, /* remot sendbuf size */
+ remote_send_size, /* how large were the recvs */
+ elapsed_time, /* how long did it take */
+ thruput, /* how fast did it go */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* TCP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+ /* this stuff needs to be worked-out in the presence of confidence */
+ /* intervals and multiple iterations of the test... raj 11/94 */
+
+ fprintf(where,
+ ksink_fmt,
+ "Bytes",
+ "Bytes",
+ "Bytes",
+ local_recv_align,
+ remote_recv_align,
+ local_recv_offset,
+ remote_recv_offset,
+ bytes_received,
+ bytes_received / (double)local_receive_calls,
+ local_receive_calls,
+ remote_bytes_sent / (double)remote_send_calls,
+ remote_send_calls);
+ fprintf(where,
+ ksink_fmt2,
+ transport_mss);
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\n\nHistogram of time spent in recv() call.\n");
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+ fflush(where);
+ }
+ }
+}
+
+
+void
+send_tcp_rr(char remote_host[]) {
+
+ char *tput_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans.\n\
+Send Recv Size Size Time Rate \n\
+bytes Bytes bytes bytes secs. per sec \n\n";
+
+ char *tput_title_band = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed \n\
+Send Recv Size Size Time Throughput \n\
+bytes Bytes bytes bytes secs. %s/sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f %s\n";
+
+ char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n";
+ char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *cpu_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time Rate local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
+
+ char *cpu_title_tput = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Tput CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time %-8.8s local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %c %% %c us/KB us/KB\n\n";
+
+ char *cpu_title_latency = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Latency CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time usecs local remote local remote\n\
+bytes bytes bytes bytes secs. per tran %% %c %% %c us/Tr us/Tr\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f %c %s\n";
+
+ char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
+
+ char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *ksink_fmt = "\
+Alignment Offset RoundTrip Trans Throughput\n\
+Local Remote Local Remote Latency Rate %-8.8s/s\n\
+Send Recv Send Recv usec/Tran per sec Outbound Inbound\n\
+%5d %5d %5d %5d %-6.3f %-6.3f %-6.3f %-6.3f\n";
+
+ send_omni_inner(remote_host, legacy, "MIGRATED TCP REQUEST/RESPONSE TEST");
+
+ if (legacy) {
+ /* We are now ready to print all the information. If the user has
+ specified zero-level verbosity, we will just print the local
+ service demand, or the remote service demand. If the user has
+ requested verbosity level 1, he will get the basic "streamperf"
+ numbers. If the user has specified a verbosity of greater than 1,
+ we will display a veritable plethora of background information
+ from outside of this block as it it not cpu_measurement
+ specific... */
+
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ remote_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ if ('x' == libfmt) {
+ fprintf(where,
+ cpu_title,
+ local_cpu_method,
+ remote_cpu_method);
+ }
+ else {
+ fprintf(where,
+ cpu_title_tput,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
+ }
+
+ fprintf(where,
+ cpu_fmt_1_line_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* guess */
+ elapsed_time, /* how long was the test */
+ thruput,
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand, /* remote service demand */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ fprintf(where,
+ cpu_fmt_1_line_2,
+ rss_size,
+ rsr_size);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ ('x' == libfmt) ? tput_title : tput_title_band,
+ format_units());
+ }
+
+ fprintf(where,
+ tput_fmt_1_line_1, /* the format string */
+ lss_size,
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* how large were the responses */
+ elapsed_time, /* how long did it take */
+ /* are we trans or do we need to convert to bytes then
+ bits? at this point, thruput is in our "confident"
+ transactions per second. we can convert to a
+ bidirectional bitrate by multiplying that by the sum
+ of the req_size and rsp_size. we pass that to
+ calc_thruput_interval_omni with an elapsed time of
+ 1.0 s to get it converted to [kmg]bits/s or
+ [KMG]Bytes/s */
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ fprintf(where,
+ tput_fmt_1_line_2,
+ rss_size, /* remote recvbuf size */
+ rsr_size);
+
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ /* how to handle the verbose information in the presence of */
+ /* confidence intervals is yet to be determined... raj 11/94 */
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* TCP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+ /* normally, you might think that if we were messing about with
+ the value of libfmt we would need to put it back again, but
+ since this is basically the last thing we are going to do with
+ it, it does not matter. so there :) raj 2007-06-08 */
+ /* if the user was asking for transactions, then we report
+ megabits per second for the unidirectional throughput,
+ otherwise we use the desired units. */
+ if ('x' == libfmt) {
+ libfmt = 'm';
+ }
+
+ fprintf(where,
+ ksink_fmt,
+ format_units(),
+ local_send_align,
+ remote_recv_offset,
+ local_send_offset,
+ remote_recv_offset,
+ /* if the user has enable burst mode, we have to remember
+ to account for that in the number of transactions
+ outstanding at any one time. otherwise we will
+ underreport the latency of individual
+ transactions. learned from saf by raj 2007-06-08 */
+ (((double)1.0/transaction_rate)*(double)1000000.0) *
+ (double) (1 + ((first_burst_size > 0) ? first_burst_size : 0)),
+ transaction_rate,
+ calc_thruput_interval_omni(transaction_rate * (double)req_size,
+ 1.0),
+ calc_thruput_interval_omni(transaction_rate * (double)rsp_size,
+ 1.0));
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\nHistogram of request/response times\n");
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+ fflush(where);
+ }
+ }
+}
+
+
+void
+send_tcp_conn_rr(char remote_host[])
+{
+
+ char *tput_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans.\n\
+Send Recv Size Size Time Rate \n\
+bytes Bytes bytes bytes secs. per sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f\n";
+
+ char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
+ char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *cpu_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time Rate local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f\n";
+
+ char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
+
+ char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *ksink_fmt = "\n\
+Alignment Offset\n\
+Local Remote Local Remote\n\
+Send Recv Send Recv\n\
+%5d %5d %5d %5d\n";
+
+ send_omni_inner(remote_host,
+ legacy,
+ "MIGRATED TCP Connect/Request/Response TEST");
+
+ /* We are now ready to print all the information. If the user */
+ /* has specified zero-level verbosity, we will just print the */
+ /* local service demand, or the remote service demand. If the */
+ /* user has requested verbosity level 1, he will get the basic */
+ /* "streamperf" numbers. If the user has specified a verbosity */
+ /* of greater than 1, we will display a veritable plethora of */
+ /* background information from outside of this block as it it */
+ /* not cpu_measurement specific... */
+
+ if (legacy) {
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ remote_cpu_method);
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ cpu_title,
+ local_cpu_method,
+ remote_cpu_method);
+ }
+
+ fprintf(where,
+ cpu_fmt_1_line_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* guess */
+ elapsed_time, /* how long was the test */
+ thruput,
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand); /* remote service demand */
+ fprintf(where,
+ cpu_fmt_1_line_2,
+ rss_size,
+ rsr_size);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ thruput);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,tput_title,format_units());
+ }
+
+ fprintf(where,
+ tput_fmt_1_line_1, /* the format string */
+ lss_size,
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* how large were the responses */
+ elapsed_time, /* how long did it take */
+ thruput);
+ fprintf(where,
+ tput_fmt_1_line_2,
+ rss_size, /* remote recvbuf size */
+ rsr_size);
+
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ /* how to handle the verbose information in the presence of */
+ /* confidence intervals is yet to be determined... raj 11/94 */
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* TCP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+ fprintf(where,
+ ksink_fmt,
+ local_send_align,
+ remote_recv_align,
+ local_send_offset,
+ remote_recv_offset);
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\nHistogram of request/response times\n");
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+ fflush(where);
+ }
+ }
+}
+
+void
+send_udp_stream(char remote_host[])
+{
+ /**********************************************************************/
+ /* */
+ /* UDP Unidirectional Send Test */
+ /* */
+ /**********************************************************************/
+
+ char *tput_title = "\
+Socket Message Elapsed Messages \n\
+Size Size Time Okay Errors Throughput\n\
+bytes bytes secs # # %s/sec\n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f\n";
+
+ char *tput_fmt_1 = "\
+%6d %6d %-7.2f %7"PRIu64" %6d %7.2f\n\
+%6d %-7.2f %7"PRIu64" %7.2f\n\n";
+
+
+ char *cpu_title = "\
+Socket Message Elapsed Messages CPU Service\n\
+Size Size Time Okay Errors Throughput Util Demand\n\
+bytes bytes secs # # %s/sec %% %c%c us/KB\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.2f %c\n";
+
+ char *cpu_fmt_1 = "\
+%6d %6d %-7.2f %7"PRIu64" %6d %7.1f %-6.2f %-6.3f\n\
+%6d %-7.2f %7"PRIu64" %7.1f %-6.2f %-6.3f\n\n";
+
+
+ send_omni_inner(remote_host, legacy, "MIGRATED UDP STREAM TEST");
+
+ if (legacy) {
+ /* We are now ready to print all the information. If the user has
+ specified zero-level verbosity, we will just print the local
+ service demand, or the remote service demand. If the user has
+ requested verbosity level 1, he will get the basic "streamperf"
+ numbers. If the user has specified a verbosity of greater than
+ 1, we will display a veritable plethora of background
+ information from outside of this block as it it not
+ cpu_measurement specific... */
+
+
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ local_cpu_method);
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ cpu_title,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
+
+ fprintf(where,
+ cpu_fmt_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ send_size, /* how large were the sends */
+ elapsed_time, /* how long was the test */
+ local_send_calls,
+ failed_sends,
+ local_send_thruput, /* what was the xfer rate */
+ local_cpu_utilization, /* local cpu */
+ local_service_demand, /* local service demand */
+ rsr_size,
+ elapsed_time,
+ remote_receive_calls,
+ remote_recv_thruput,
+ remote_cpu_utilization, /* remote cpu */
+ remote_service_demand); /* remote service demand */
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ local_send_thruput);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,tput_title,format_units());
+ }
+ fprintf(where,
+ tput_fmt_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ send_size, /* how large were the sends */
+ elapsed_time, /* how long did it take */
+ local_send_calls,
+ failed_sends,
+ local_send_thruput,
+ rsr_size, /* remote recvbuf size */
+ elapsed_time,
+ remote_receive_calls,
+ remote_recv_thruput);
+ break;
+ }
+ }
+
+#ifdef WANT_HISTOGRAM
+ if (verbosity > 1) {
+ fprintf(where,"\nHistogram of time spent in send() call\n");
+ HIST_report(time_hist);
+ }
+#endif /* WANT_HISTOGRAM */
+ fflush(where);
+ }
+}
+
+void
+send_udp_rr(char remote_host[])
+{
+
+ char *tput_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans.\n\
+Send Recv Size Size Time Rate \n\
+bytes Bytes bytes bytes secs. per sec \n\n";
+
+ char *tput_title_band = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed \n\
+Send Recv Size Size Time Throughput \n\
+bytes Bytes bytes bytes secs. %s/sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f %s\n";
+
+ char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n";
+
+ char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *cpu_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time Rate local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
+
+ char *cpu_title_tput = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Tput CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time %-8.8s local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %c %% %c us/KB us/KB\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f %c %s\n";
+
+ char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
+
+ char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ send_omni_inner(remote_host, legacy, "MIGRATED UDP REQUEST/RESPONSE TEST");
+
+ if (legacy) {
+ /* We are now ready to print all the information. If the user has
+ specified zero-level verbosity, we will just print the local
+ service demand, or the remote service demand. If the user has
+ requested verbosity level 1, he will get the basic "streamperf"
+ numbers. If the user has specified a verbosity of greater than
+ 1, we will display a veritable plethora of background
+ information from outside of this block as it it not
+ cpu_measurement specific... */
+
+ if (confidence < 0) {
+ /* we did not hit confidence, but were we asked to look for it? */
+ if (iteration_max > 1) {
+ display_confidence();
+ }
+ }
+
+ if (local_cpu_usage || remote_cpu_usage) {
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand,
+ local_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand,
+ remote_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+
+ }
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ if ('x' == libfmt) {
+ fprintf(where,
+ cpu_title,
+ local_cpu_method,
+ remote_cpu_method);
+ }
+ else {
+ fprintf(where,
+ cpu_title_tput,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
+ }
+
+ fprintf(where,
+ cpu_fmt_1_line_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* guess */
+ elapsed_time, /* how long was the test */
+ thruput,
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand, /* remote service demand */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ fprintf(where,
+ cpu_fmt_1_line_2,
+ rss_size,
+ rsr_size);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,
+ ('x' == libfmt) ? tput_title : tput_title_band,
+ format_units());
+ }
+
+ fprintf(where,
+ tput_fmt_1_line_1, /* the format string */
+ lss_size,
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* how large were the responses */
+ elapsed_time, /* how long did it take */
+ thruput,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+ fprintf(where,
+ tput_fmt_1_line_2,
+ rss_size, /* remote recvbuf size */
+ rsr_size);
+
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ /* how to handle the verbose information in the presence of */
+ /* confidence intervals is yet to be determined... raj 11/94 */
+
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* UDP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\nHistogram of request/reponse times.\n");
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+ }
+ fflush(where);
+ }
+}
+
+
+#endif /* WANT_MIGRATION */
+
+
+/* using legacy test names will cause certain default settings to be
+ made before we scan the test-specific arguments. raj 2010-07-20 */
+static void
+set_omni_defaults_by_legacy_testname() {
+
+ /* the uber defaults are for a unidirectional test using TCP */
+ protocol = IPPROTO_TCP;
+ socket_type = SOCK_STREAM;
+ connection_test = 0;
+ req_size = rsp_size = -1;
+ was_legacy = 1;
+ legacy = 1;
+ implicit_direction = 0; /* do we allow certain options to
+ implicitly affect the test direction? */
+ if (strcasecmp(test_name,"TCP_STREAM") == 0) {
+ direction = NETPERF_XMIT;
+ }
+ else if (strcasecmp(test_name,"TCP_MAERTS") == 0) {
+ direction = NETPERF_RECV;
+ }
+ else if (strcasecmp(test_name,"TCP_RR") == 0) {
+ req_size = rsp_size = 1;
+ direction = 0;
+ direction |= NETPERF_XMIT;
+ direction |= NETPERF_RECV;
+ }
+ else if (strcasecmp(test_name,"UDP_STREAM") == 0) {
+ protocol = IPPROTO_UDP;
+ socket_type = SOCK_DGRAM;
+ }
+ else if (strcasecmp(test_name,"UDP_RR") == 0) {
+ protocol = IPPROTO_UDP;
+ socket_type = SOCK_DGRAM;
+ direction = 0;
+ direction |= NETPERF_XMIT;
+ direction |= NETPERF_RECV;
+ req_size = rsp_size = 1;
+ }
+ else if (strcasecmp(test_name,"TCP_CC") == 0) {
+ direction = 0;
+ connection_test = 1;
+ }
+ else if (strcasecmp(test_name,"TCP_CRR") == 0) {
+ direction = 0;
+ direction |= NETPERF_XMIT;
+ direction |= NETPERF_RECV;
+ req_size = rsp_size = 1;
+ connection_test = 1;
+ }
+ else if (strcasecmp(test_name,"omni") == 0) {
+ /* there is not much to do here but clear the legacy flag */
+ was_legacy = 0;
+ legacy = 0;
+ implicit_direction = 1;
+ }
+ socket_type_str = hst_to_str(socket_type);
+}
+
+char omni_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+OMNI and Migrated BSD Sockets Test Options:\n\
+ -b number Send number requests at start of _RR tests\n\
+ -c Explicitly declare this a connection test such as\n\
+ TCP_CRR or TCP_CC\n\
+ -C Set TCP_CORK when available\n\
+ -d direction Explicitly set test direction based on bitwise OR\n\
+ of 0x2 for transmit and 0x4 for receive. Default:\n\
+ based on test type\n\
+ -D [L][,R] Set TCP_NODELAY locally and/or remotely (TCP_*)\n\
+ -h Display this text\n\
+ -H name[/mask],fam Use name (or IP) and family as target of data connection\n\
+ A mask value will cause randomization of the IP used\n\
+ -k [file] Generate keyval output optionally based on file\n\
+ Use filename of '?' to get the list of choices\n\
+ -K loc[,rem] Set the local and/or remote congestion control\n\
+ algorithm to use on those platforms where it can\n\
+ be set.\n\
+ -L name[/mask],fam Use name (or IP) and family as source of data connection\n\
+ A mask value will cause randomization of the IP used\n\
+ -m local,remote Set the send size for _STREAM/_MAERTS tests\n\
+ -M local,remote Set the recv size for _STREAM/_MAERTS tests\n\
+ -n Use the connected socket for UDP locally\n\
+ -N Use the connected socket for UDP remotely\n\
+ -o [file] Generate CSV output optionally based on file\n\
+ Use filename of '?' to get the list of choices\n\
+ -O [file] Generate classic-style output based on file\n\
+ Use filename of '?' to get the list of choices\n\
+ -p min[,max] Set the min/max port numbers for TCP_CRR, TCP_TRR\n\
+ -P local[,remote] Set the local/remote port for the data socket\n\
+ -r req,[rsp] Set request/response sizes (TCP_RR, UDP_RR)\n\
+ -R 0/1 Allow routing of traffic on data connection.\n\
+ Default: 0 (off) for UDP_STREAM, 1 (on) otherwise\n\
+ -s send[,recv] Set local socket send/recv buffer sizes\n\
+ -S send[,recv] Set remote socket send/recv buffer sizes\n\
+ -t type Explicitly set socket type. Default is implicit\n\
+ based on other settings\n\
+ -T protocol Explicitly set data connection protocol. Default is\n\
+ implicit based on other settings\n\
+ -u uuid Use the supplied string as the UUID for this test.\n\
+ -4 Use AF_INET (eg IPv4) on both ends of the data conn\n\
+ -6 Use AF_INET6 (eg IPv6) on both ends of the data conn\n\
+\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";
+
+void
+print_omni_usage()
+{
+
+ fwrite(omni_usage, sizeof(char), strlen(omni_usage), stdout);
+ exit(1);
+
+}
+
+
+void
+scan_omni_args(int argc, char *argv[])
+
+{
+
+#define OMNI_ARGS "aBb:cCd:De:FgG:hH:i:Ij:kK:l:L:m:M:nNoOp:P:r:R:s:S:t:T:u:UVw:W:46"
+
+ extern char *optarg; /* pointer to option string */
+
+ int c;
+ int have_uuid = 0;
+ int have_R_option = 0;
+
+ char
+ arg1[BUFSIZ], /* argument holders */
+ arg2[BUFSIZ],
+ arg3[BUFSIZ];
+
+ if (debug) {
+ int i;
+ printf("%s called with the following argument vector\n",
+ __FUNCTION__);
+ for (i = 0; i< argc; i++) {
+ printf("%s ",argv[i]);
+ }
+ printf("\n");
+ }
+
+ /* double-check struct sizes */
+ {
+ const union netperf_request_struct * u = (const union netperf_request_struct *)0;
+ if (debug) {
+ fprintf(where, "sizeof(omni_request_struct)=%d/%d\n",
+ (int)sizeof(struct omni_request_struct),
+ (int)sizeof(u->content.test_specific_data));
+ fprintf(where, "sizeof(omni_response_struct)=%d/%d\n",
+ (int)sizeof(struct omni_response_struct),
+ (int)sizeof(u->content.test_specific_data));
+ fprintf(where, "sizeof(omni_results_struct)=%d/%d\n",
+ (int)sizeof(struct omni_results_struct),
+ (int)sizeof(u->content.test_specific_data));
+ }
+ assert(sizeof(struct omni_request_struct)
+ <= sizeof(u->content.test_specific_data));
+ assert(sizeof(struct omni_response_struct)
+ <= sizeof(u->content.test_specific_data));
+ assert(sizeof(struct omni_results_struct)
+ <= sizeof(u->content.test_specific_data));
+ }
+
+ strncpy(local_data_port,"0",sizeof(local_data_port));
+ strncpy(remote_data_port,"0",sizeof(remote_data_port));
+
+ /* this will handle setting default settings based on test name */
+ set_omni_defaults_by_legacy_testname();
+
+ /* 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, OMNI_ARGS)) != EOF) {
+ switch (c) {
+ case '?':
+ case '4':
+ remote_data_family = AF_INET;
+ local_data_family = AF_INET;
+ break;
+ case '6':
+#if defined(AF_INET6)
+ remote_data_family = AF_INET6;
+ local_data_family = AF_INET6;
+#else
+ fprintf(stderr,
+ "This netperf was not compiled on an IPv6 capable host!\n");
+ fflush(stderr);
+ exit(-1);
+#endif
+ break;
+ case 'h':
+ print_omni_usage();
+ exit(1);
+ case 'a':
+ want_defer_accept = 1;
+ break;
+ case 'B':
+ want_use_pktinfo = 1;
+ break;
+ case 'b':
+#ifdef WANT_FIRST_BURST
+ first_burst_size = atoi(optarg);
+#else /* WANT_FIRST_BURST */
+ printf("Initial request burst functionality not compiled-in!\n");
+#endif /* WANT_FIRST_BURST */
+ break;
+ case 'c':
+ /* this is a connection test */
+ connection_test = 1;
+ break;
+ case 'C':
+#ifdef TCP_CORK
+ /* set TCP_CORK */
+ loc_tcpcork = 1;
+ rem_tcpcork = 1; /* however, at first, we ony have cork affect loc */
+#else
+ printf("WARNING: TCP_CORK not available on this platform!\n");
+#endif /* TCP_CORK */
+ break;
+ case 'd':
+ /* arbitrarily set the direction variable, but only for an
+ actual omni test and then disable implicit setting of
+ direction */
+ if (!was_legacy) {
+ direction = parse_direction(optarg);
+ implicit_direction = 0;
+ }
+ break;
+ case 'D':
+ /* set the TCP nodelay flag */
+ loc_nodelay = 1;
+ rem_nodelay = 1;
+ break;
+ case 'F':
+#if defined(MSG_FASTOPEN)
+ use_fastopen = 1;
+#else
+ printf("WARNING: TCP FASTOPEN not available on this platform!\n");
+#endif
+ break;
+ case 'e':
+ /* set the rEceive timeout */
+ receive_timeout = atoi(optarg);
+ break;
+ case 'g':
+ /* enable SO_DEBUG, or at least make the attempt, on the data socket */
+ socket_debug = 1;
+ break;
+ case 'G':
+ /* set the value for a tcp_maxseG call*/
+ transport_mss_req = atoi(optarg);
+ break;
+ case 'H':
+ break_args_explicit_sep(optarg,',',arg1,arg2);
+ if (arg1[0]) {
+ /* check to see if there was a width, which we would want to
+ be arg3. for simplicities sake, we will assume the width
+ must follow the address and not the address family - ie
+ 1.2.3.4/24,inet. This means we can just pass optarg again
+ as the source rather than have to shuffle arg values. */
+ break_args_explicit_sep(optarg,'/',arg1,arg3);
+ if (arg1[0]) {
+ remote_data_address = malloc(strlen(arg1)+1);
+ strcpy(remote_data_address,arg1);
+ explicit_data_address = 1;
+ }
+ if (arg3[0]) {
+ remote_mask_len = convert(arg3);
+ }
+ }
+ if (arg2[0]) {
+ remote_data_family = parse_address_family(arg2);
+ }
+ break;
+ case 'i':
+ fprintf(stderr,"The support for check_interval has been removed because the contributing editor no longer knew what it was for\n");
+ fflush(stderr);
+ break;
+ case 'I':
+ use_write = 1;
+ break;
+ case 'j':
+ parallel_connections = atoi(optarg);
+ break;
+ case 'k':
+ netperf_output_mode = KEYVAL;
+ legacy = 0;
+ /* obliterate any previous file name */
+ if (output_selection_spec) {
+ free(output_selection_spec);
+ output_selection_spec = NULL;
+ }
+ if (argv[optind] && ((unsigned char)argv[optind][0] != '-')) {
+ /* we assume that what follows is the name of a file with the
+ list of desired output values. */
+ output_selection_spec = strdup(argv[optind]);
+ optind++;
+ /* special case - if the file name is "?" then we will emit a
+ list of the available outputs */
+ if (strcmp(output_selection_spec,"?") == 0) {
+ dump_netperf_output_choices(stdout,1);
+ exit(1);
+ }
+ }
+ break;
+ case 'K':
+ /* "Kongestion Kontrol */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ strncpy(local_cong_control_req,arg1,sizeof(local_cong_control_req));
+ if (arg2[2])
+ strncpy(remote_cong_control_req,arg2,sizeof(remote_cong_control_req));
+ break;
+ case 'l':
+ multicast_ttl = atoi(optarg);
+ break;
+ case 'L':
+ break_args_explicit_sep(optarg,',',arg1,arg2);
+ if (arg1[0]) {
+ /* check to see if there was a width, which we would want to
+ be arg3. for simplicities sake, we will assume the width
+ must follow the address and not the address family - ie
+ 1.2.3.4/24,inet. This means we can just pass optarg again
+ as the source rather than have to shuffle arg values. */
+ break_args_explicit_sep(optarg,'/',arg1,arg3);
+ if (arg1[0]) {
+ local_data_address = malloc(strlen(arg1)+1);
+ strcpy(local_data_address,arg1);
+ }
+ if (arg3[0]) {
+ local_mask_len = convert(arg3);
+ }
+ }
+ if (arg2[0]) {
+ local_data_family = parse_address_family(arg2);
+ }
+ break;
+ case 'm':
+ /* set the send size. if we set the local send size it will add
+ XMIT to direction. if we set the remote send size it will
+ add RECV to the direction. likely as not this will need some
+ additional throught */
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ send_size = convert(arg1);
+ if (implicit_direction)
+ direction |= NETPERF_XMIT;
+ }
+ if (arg2[0]) {
+ remote_send_size_req = convert(arg2);
+ if (implicit_direction)
+ direction |= NETPERF_RECV;
+ }
+ break;
+ case 'M':
+ /* set the recv sizes. if we set the local recv size it will
+ add RECV to direction. if we set the remote recv size it
+ will add XMIT to direction */
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ remote_recv_size_req = convert(arg1);
+ if (implicit_direction)
+ direction |= NETPERF_XMIT;
+ }
+ if (arg2[0]) {
+ recv_size = convert(arg2);
+ if (implicit_direction)
+ direction |= NETPERF_RECV;
+ }
+ break;
+ case 'n':
+ /* set the local socket type */
+ local_connected = 1;
+ break;
+ case 'N':
+ /* set the remote socket type */
+ remote_connected = 1;
+ break;
+ case 'o':
+ netperf_output_mode = CSV;
+ legacy = 0;
+ /* obliterate any previous file name */
+ if (output_selection_spec) {
+ free(output_selection_spec);
+ output_selection_spec = NULL;
+ }
+ if (output_selection_spec) {
+ free(output_selection_spec);
+ output_selection_spec = NULL;
+ }
+ if (argv[optind] && ((unsigned char)argv[optind][0] != '-')) {
+ /* we assume that what follows is the name of a file with the
+ list of desired output values. */
+ output_selection_spec = strdup(argv[optind]);
+ optind++;
+ /* special case - if the file name is "?" then we will emit a
+ list of the available outputs */
+ if (strcmp(output_selection_spec,"?") == 0) {
+ dump_netperf_output_choices(stdout,1);
+ exit(1);
+ }
+ }
+ break;
+ case 'O':
+ netperf_output_mode = HUMAN;
+ legacy = 0;
+ /* obliterate any previous file name */
+ if (output_selection_spec) {
+ free(output_selection_spec);
+ output_selection_spec = NULL;
+ }
+ if (argv[optind] && ((unsigned char)argv[optind][0] != '-')) {
+ /* we assume that what follows is the name of a file with the
+ list of desired output values */
+ output_selection_spec = strdup(argv[optind]);
+ optind++;
+ if (strcmp(output_selection_spec,"?") == 0) {
+ dump_netperf_output_choices(stdout,0);
+ exit(1);
+ }
+ }
+ break;
+ case 'p':
+ /* set the min and max port numbers for the TCP_CRR and TCP_TRR */
+ /* tests. */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ client_port_min = atoi(arg1);
+ if (arg2[0])
+ client_port_max = atoi(arg2);
+ break;
+ case 'P':
+ /* set the local and remote data port numbers for the tests to
+ allow them to run through those blankety blank end-to-end
+ breaking firewalls. raj 2004-06-15 */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ strncpy(local_data_port,arg1,sizeof(local_data_port));
+ if (arg2[0])
+ strncpy(remote_data_port,arg2,sizeof(remote_data_port));
+ break;
+ case 'r':
+ /* set the request/response sizes. setting request/response
+ sizes implicitly sets direction to XMIT and RECV */
+ if (implicit_direction) {
+ direction |= NETPERF_XMIT;
+ direction |= NETPERF_RECV;
+ }
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ req_size = convert(arg1);
+ if (arg2[0])
+ rsp_size = convert(arg2);
+ break;
+ case 'R':
+ routing_allowed = atoi(optarg);
+ have_R_option = 1;
+ break;
+ case 's':
+ /* set local socket sizes */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ lss_size_req = convert(arg1);
+ if (arg2[0])
+ lsr_size_req = convert(arg2);
+ break;
+ case 'S':
+ /* set remote socket sizes */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ rss_size_req = convert(arg1);
+ if (arg2[0])
+ rsr_size_req = convert(arg2);
+ break;
+ case 't':
+ /* set the socket type */
+ socket_type = parse_socket_type(optarg);
+ break;
+ case 'T':
+ /* set the protocol - aka "Transport" */
+ protocol = parse_protocol(optarg);
+ break;
+ case 'u':
+ /* use the supplied string as the UUID for this test. at some
+ point we may want to sanity check the string we are given but
+ for now we won't worry about it */
+ strncpy(test_uuid,optarg,sizeof(test_uuid));
+ /* strncpy may leave us with a string without a null at the end */
+ test_uuid[sizeof(test_uuid) - 1] = 0;
+ have_uuid = 1;
+ break;
+ case 'U':
+ /* we don't want to give-up on the failure of a connect() call */
+ dont_give_up = 1;
+ break;
+ case 'W':
+ /* set the "width" of the user space data */
+ /* buffer. This will be the number of */
+ /* send_size buffers malloc'd in the */
+ /* *_STREAM test. It may be enhanced to set */
+ /* both send and receive "widths" but for now */
+ /* it is just the sending *_STREAM. */
+ send_width = convert(optarg);
+ break;
+ case 'V' :
+ /* we want to do copy avoidance and will set */
+ /* it for everything, everywhere, if we really */
+ /* can. of course, we don't know anything */
+ /* about the remote... */
+ loc_sndavoid = 1;
+ loc_rcvavoid = 1;
+ rem_sndavoid = 1;
+ rem_rcvavoid = 1;
+ break;
+ };
+ }
+
+ /* generate the UUID for this test if the user has not supplied it */
+ if (!have_uuid)
+ get_uuid_string(test_uuid,sizeof(test_uuid));
+
+ protocol_str = protocol_to_str(protocol);
+ /* ok, if we have gone through all that, and direction is still
+ zero, let us see if it needs to be set to something else. */
+ if ((0 == direction) && (!connection_test)) direction = NETPERF_XMIT;
+ direction_str = direction_to_str(direction);
+
+ /* to cover the backside of blithering idiots who run unidirectional
+ UDP tests on test setups where they might trash their corporate
+ WAN, we grudgingly provide a safety latch. unless explicitly
+ enabled, UDP_STREAM/UDP_MAERTS sockets will not allow themselves
+ to be routed via a gateway. raj 20091026 */
+
+ if ((!have_R_option) &&
+ (protocol == IPPROTO_UDP) &&
+ (!NETPERF_IS_RR(direction))) {
+ routing_allowed = 0;
+ }
+
+ /* some other sanity checks we need to make would include stuff when
+ the user has set -m and -M such that both XMIT and RECV are set
+ and has not set -r. initially we will not allow that. at some
+ point we might allow that if the user has also set -r, but until
+ then the code will simply ignore the values from -m and -M when
+ -r is set. */
+
+#if defined(WANT_HISTOGRAM)
+ if (verbosity > 1) keep_histogram = 1;
+#endif
+
+ /* did the user use -d 6 but not set -r? */
+ if (NETPERF_IS_RR(direction) && !NETPERF_CC(direction)) {
+ if (req_size == -1)
+ req_size = 1;
+ if (rsp_size == -1)
+ rsp_size = 1;
+ }
+
+ /* ok, time to sanity check the output units */
+ if ('?' == libfmt) {
+ /* if this is a RR test then set it to 'x' for transactions */
+ if (NETPERF_IS_RR(direction)) {
+ 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 (!NETPERF_IS_RR(direction)) {
+ libfmt = 'm';
+ }
+ }
+
+ /* this needs to be strdup :) */
+ thruput_format_str = strdup(format_units());
+
+ /* so, if there is to be no control connection, we want to have some
+ different settings for a few things */
+
+ if (no_control) {
+ if (strcmp(remote_data_port,"0") == 0) {
+ /* we need to select either the discard port, echo port or
+ chargen port dedepending on the test direction. raj
+ 20101220 */
+ if (NETPERF_XMIT_ONLY(direction)) {
+ strncpy(remote_data_port,"discard",sizeof(remote_data_port));
+ recv_size = -1;
+ }
+ else if (NETPERF_RECV_ONLY(direction)) {
+ strncpy(remote_data_port,"chargen",sizeof(remote_data_port));
+ send_size = -1;
+ }
+ else if (NETPERF_IS_RR(direction) || NETPERF_CC(direction)) {
+ strncpy(remote_data_port,"echo",sizeof(remote_data_port));
+ rsp_size = req_size;
+ }
+ else {
+ printf("No default port known for the %s test, please set one yourself\n",test_name);
+ exit(-1);
+ }
+ }
+ remote_data_port[sizeof(remote_data_port) - 1] = '\0';
+
+ /* I go back and forth on whether these should become -1 or if
+ they should become 0 for a no_control test. what do you think?
+ raj 2006-02-08 */
+
+ rem_rcvavoid = -1;
+ rem_sndavoid = -1;
+ rss_size_req = -1;
+ rsr_size_req = -1;
+ rem_nodelay = -1;
+
+ }
+ /* so, did the user request a few things implicitly via output selection? */
+ if (!legacy)
+ print_omni_init();
+
+ if (desired_output_groups & OMNI_WANT_STATS) {
+ keep_statistics = 1;
+ keep_histogram = 1;
+ }
+
+}
+
+#endif /* WANT_OMNI */