/*
* Copyright (C) 2000, 2001 Nominum, Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (C) 2004 - 2015 Nominum, Inc.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice and this permission notice
* appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/***
*** DNS Performance Testing Tool
***
*** Version $Id: dnsperf.c 263303 2015-12-15 01:09:36Z bwelling $
***/
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define ISC_BUFFER_USEINLINE
#include <isc/sockaddr.h>
#include "net.h"
#include "datafile.h"
#include "dns.h"
#include "log.h"
#include "opt.h"
#include "os.h"
#include "util.h"
#include "version.h"
#define DEFAULT_LOCAL_PORT 0
typedef struct {
int argc;
char **argv;
int family;
} config_t;
typedef struct {
} times_t;
typedef struct {
} stats_t;
typedef struct query_info {
char *desc;
int sock;
/*
* This link links the query into the list of outstanding
* queries or the list of available query IDs.
*/
} query_info;
typedef struct {
unsigned int nsocks;
int current_sock;
int *socks;
} threadinfo_t;
static void
{
(void)sig;
}
static void
{
int i;
printf("[Status] Command line: %s",
printf("\n");
printf("[Status] Sending %s (to %s)\n",
printf("[Status] Stopping after ");
printf("%u.%06u seconds",
printf(" or ");
printf("\n");
}
static void
{
const char *reason;
if (interrupted)
reason = "interruption";
reason = "end of file";
else
reason = "time limit";
printf("\n");
}
static double
{
double squared;
}
static void
{
const char *units;
unsigned int i;
printf("Statistics:\n\n");
if (stats->num_interrupted > 0)
"(%.2lf%%)\n",
printf("\n");
printf(" Response codes: ");
for (i = 0; i < 16; i++) {
if (stats->rcodecounts[i] == 0)
continue;
if (first_rcode)
else
printf(", ");
}
printf("\n");
printf(" Average packet size: request %u, response %u\n",
stats->num_completed));
printf(" Run time (s): %u.%06u\n",
printf("\n");
printf(" Average Latency (s): %u.%06u (min %u.%06u, max %u.%06u)\n",
(unsigned int)(latency_avg / MILLION),
(unsigned int)(latency_avg % MILLION),
printf(" Latency StdDev (s): %f\n",
}
printf("\n");
}
static void
{
unsigned int i, j;
for (j = 0; j < 16; j++)
}
}
static char *
{
return buf;
}
static void
{
if (result != ISC_R_SUCCESS)
perf_log_fatal("creating memory context: %s",
"address family of DNS transport, inet or inet6", "any",
&family);
"the port on which to query the server",
"the local address from which to send queries", NULL,
&local_name);
"the local port from which to send queries",
"the number of clients to act as", NULL,
"the number of threads to run", NULL,
"run through input at most N times", NULL,
"run for at most this many seconds", NULL,
"the timeout for query completion in seconds",
"set the DNSSEC OK bit (implies EDNS)", NULL,
"the TSIG algorithm, name and secret", NULL,
&tsigkey);
"the maximum number of queries outstanding",
"limit the number of queries per second", NULL,
"print qps statistics every N seconds",
"send dynamic updates instead of queries",
"verbose: report each query to stdout",
&config->server_addr);
/*
* If we run more threads than max-qps, some threads will have
* ->max_qps set to 0, and be unlimited.
*/
/*
* We also can't run more threads than clients.
*/
}
static void
{
unsigned int i;
for (i = 0; i < 2; i++) {
close(threadpipe[i]);
}
}
typedef enum {
static inline void
{
switch (op) {
case prepend_unused:
break;
case append_unused:
break;
case prepend_outstanding:
break;
}
}
static inline isc_uint64_t
{
}
static void
wait_for_start(void)
{
LOCK(&start_lock);
while (!started)
UNLOCK(&start_lock);
}
static void *
{
unsigned int max_packet_size;
query_info *q;
int qid;
unsigned char *base;
unsigned int length;
int n;
/* Avoid flooding the network too quickly. */
{
if (stats->num_completed == 0)
usleep(1000);
else
sleep(0);
}
/* Rate limiting */
continue;
}
}
/* Limit in-flight queries */
continue;
}
q->timestamp = ISC_UINT64_MAX;
if (result != ISC_R_SUCCESS) {
if (result == ISC_R_INVALIDFILE)
perf_log_fatal("input file contains no data");
break;
}
(isc_textregion_t *) &used,
&msg);
if (result != ISC_R_SUCCESS) {
continue;
}
perf_log_fatal("out of memory");
}
if (n < 0 || (unsigned int) n != length) {
perf_log_warning("failed to send packet: %s",
continue;
}
}
return NULL;
}
static void
{
struct query_info *q;
/* Avoid locking unless we need to. */
return;
do {
} else {
perf_log_printf("[Timeout] %s timed out: msg id %u",
}
}
typedef struct {
int sock;
unsigned int size;
char *desc;
static isc_boolean_t
unsigned char *packet_buffer, unsigned int packet_size,
{
int s;
int n;
if (n < 0) {
*saved_errnop = errno;
return ISC_FALSE;
}
return ISC_TRUE;
}
static inline void
{
}
static inline isc_boolean_t
{
unsigned int shift;
return ISC_TRUE;
return ISC_FALSE;
}
static void *
{
unsigned int nrecvd;
int saved_errno;
query_info *q;
unsigned int i, j;
last_socket = 0;
while (!interrupted) {
/*
* If we're done sending and either all responses have been
* received, stop.
*/
break;
/*
* Try to receive a few packets, so that we can process them
* atomically.
*/
saved_errno = 0;
for (i = 0; i < RECV_BATCH_SIZE; i++) {
current_socket = (j + last_socket) %
continue;
sizeof(packet_buffer),
&recvd[i], &saved_errno))
{
break;
}
if (saved_errno != EAGAIN)
break;
}
break;
}
nrecvd = i;
/* Do all of the processing that requires the lock */
for (i = 0; i < nrecvd; i++) {
if (recvd[i].short_response)
continue;
q->timestamp == ISC_UINT64_MAX ||
{
continue;
}
}
/* Now do the rest of the processing unlocked */
for (i = 0; i < nrecvd; i++) {
if (recvd[i].short_response) {
perf_log_warning("received short response");
continue;
}
if (recvd[i].unexpected) {
perf_log_warning("received a response with an "
"unexpected (maybe timed out) "
continue;
}
"> %s %s %u.%06u",
}
stats->num_completed++;
}
if (nrecvd > 0)
/*
* If there was an error, handle it (by either ignoring it,
* blocking, or exiting).
*/
if (nrecvd < RECV_BATCH_SIZE) {
if (saved_errno == EINTR) {
continue;
} else if (saved_errno == EAGAIN) {
threadpipe[0],
continue;
} else {
perf_log_fatal("failed to receive packet: %s",
}
}
}
return NULL;
}
static void *
{
double qps;
last_completed = 0;
{
perf_log_printf("%u.%06u: %.6lf",
}
return NULL;
}
static void
{
struct query_info *q;
while (ISC_TRUE) {
if (q == NULL)
break;
if (q->timestamp == ISC_UINT64_MAX)
continue;
}
}
}
static isc_uint32_t
{
value++;
return value;
}
static void
{
for (i = 0; i < NQIDS; i++) {
}
/*
* Compute per-thread limits based on global values.
*/
/*
* We can't have more than 64k outstanding queries per thread.
*/
perf_log_fatal("out of memory");
socket_offset = 0;
for (i = 0; i < offset; i++)
&config->local_addr,
tinfo->current_sock = 0;
}
static void
{
}
static void
{
unsigned int i;
if (interrupted)
}
int
{
unsigned int i;
printf("DNS Performance Testing Tool\n"
perf_log_fatal("creating pipe");
perf_log_fatal("out of memory");
if (config.stats_interval > 0) {
}
else
LOCK(&start_lock);
UNLOCK(&start_lock);
if (result == ISC_R_CANCELED)
threadinfo_stop(&threads[i]);
if (config.stats_interval > 0)
return (0);
}