1303980Sngie/*	$NetBSD: in_cksum.c,v 1.5 2015/10/18 18:27:25 christos Exp $	*/
2303980Sngie/*-
3303980Sngie * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
4303980Sngie * All rights reserved.
5303980Sngie *
6303980Sngie * Redistribution and use in source and binary forms, with or without
7303980Sngie * modification, are permitted provided that the following conditions
8303980Sngie * are met:
9303980Sngie *
10303980Sngie * 1. Redistributions of source code must retain the above copyright
11303980Sngie *    notice, this list of conditions and the following disclaimer.
12303980Sngie * 2. Redistributions in binary form must reproduce the above copyright
13303980Sngie *    notice, this list of conditions and the following disclaimer in
14303980Sngie *    the documentation and/or other materials provided with the
15303980Sngie *    distribution.
16303980Sngie *
17303980Sngie * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18303980Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19303980Sngie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20303980Sngie * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
21303980Sngie * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22303980Sngie * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
23303980Sngie * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24303980Sngie * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25303980Sngie * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26303980Sngie * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27303980Sngie * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28303980Sngie * SUCH DAMAGE.
29303980Sngie */
30303980Sngie
31303980Sngie#include <sys/cdefs.h>
32303980Sngie__KERNEL_RCSID(0, "$NetBSD: in_cksum.c,v 1.5 2015/10/18 18:27:25 christos Exp $");
33303980Sngie
34303980Sngie#include <sys/param.h>
35303980Sngie#include <sys/mbuf.h>
36303980Sngie#include <sys/resource.h>
37303980Sngie#include <err.h>
38303980Sngie#include <stdbool.h>
39303980Sngie#include <stdio.h>
40303980Sngie#include <stdarg.h>
41303980Sngie#include <unistd.h>
42303980Sngie#include <stdlib.h>
43303980Sngie#include <string.h>
44303980Sngie
45303980Sngie#define cpu_in_cksum portable_cpu_in_cksum
46303980Sngie#include "cpu_in_cksum.c"
47303980Sngie
48303980Sngie#ifdef HAVE_CPU_IN_CKSUM
49303980Sngie#undef cpu_in_cksum
50303980Sngieint	cpu_in_cksum(struct mbuf*, int, int, uint32_t);
51303980Sngie#endif
52303980Sngie
53303980Sngiestatic bool	random_aligned;
54303980Sngie
55303980Sngievoid panic(const char *, ...) __printflike(1, 2);
56303980Sngievoid
57303980Sngiepanic(const char *fmt, ...)
58303980Sngie{
59303980Sngie	va_list ap;
60303980Sngie	va_start(ap, fmt);
61303980Sngie	verrx(1, fmt, ap);
62303980Sngie	va_end(ap);
63303980Sngie}
64303980Sngie
65303980Sngiestatic void
66303980Sngiefree_mbuf_chain(struct mbuf *m)
67303980Sngie{
68303980Sngie	struct mbuf *next;
69303980Sngie
70303980Sngie	if (m == NULL)
71303980Sngie		return;
72303980Sngie
73303980Sngie	next = m->m_next;
74303980Sngie	free(m);
75303980Sngie	free_mbuf_chain(next);
76303980Sngie}
77303980Sngie
78303980Sngiestatic struct mbuf *
79303980Sngieallocate_mbuf_chain(char **lens)
80303980Sngie{
81303980Sngie	int len, off;
82303980Sngie	struct mbuf *m;
83303980Sngie
84303980Sngie	if (*lens == NULL)
85303980Sngie		return NULL;
86303980Sngie
87303980Sngie	len = atoi(*lens);
88303980Sngie	off = random_aligned ? rand() % 64 : 0;
89303980Sngie
90303980Sngie	m = malloc(sizeof(struct m_hdr) + len + off);
91303980Sngie	if (m == NULL)
92303980Sngie		err(EXIT_FAILURE, "malloc failed");
93303980Sngie
94303980Sngie	m->m_data = (char *)m + sizeof(struct m_hdr) + off;
95303980Sngie	m->m_len = len;
96303980Sngie
97303980Sngie	m->m_next = allocate_mbuf_chain(lens + 1);
98303980Sngie
99303980Sngie	return m;
100303980Sngie}
101303980Sngie
102303980Sngie#ifdef MBUFDUMP
103303980Sngiestatic void
104303980Sngiedump_mbuf(const struct mbuf *m, int len, int off)
105303980Sngie{
106303980Sngie	int x = 0;
107303980Sngie	if (len <= 0)
108303980Sngie		return;
109303980Sngie
110303980Sngie	printf("Starting len=%d off=%d:\n", len, off);
111303980Sngie	if (off > 0) {
112303980Sngie		for (; m; m = m->m_next)
113303980Sngie			if (off > m->m_len)
114303980Sngie				off -= m->m_len;
115303980Sngie			else
116303980Sngie				break;
117303980Sngie		if (m == NULL || off > m->m_len)
118303980Sngie			errx(1, "out of data");
119303980Sngie	}
120303980Sngie
121303980Sngie	unsigned char *ptr = mtod(m, unsigned char *) + off;
122303980Sngie	unsigned char *eptr = ptr + m->m_len;
123303980Sngie	printf("[");
124303980Sngie	for (;;) {
125303980Sngie		if (ptr == eptr) {
126303980Sngie			m = m->m_next;
127303980Sngie			if (m == NULL)
128303980Sngie				errx(1, "out of data");
129303980Sngie			ptr = mtod(m, unsigned char *);
130303980Sngie			eptr = ptr + m->m_len;
131303980Sngie			printf("]\n[");
132303980Sngie			x = 0;
133303980Sngie		}
134303980Sngie		printf("%.2x ", *ptr++);
135303980Sngie		if (++x % 16 == 0)
136303980Sngie			printf("\n");
137303980Sngie		if (--len == 0)
138303980Sngie			break;
139303980Sngie	}
140303980Sngie	printf("]\n");
141303980Sngie	fflush(stdout);
142303980Sngie}
143303980Sngie#endif
144303980Sngie
145303980Sngiestatic void
146303980Sngierandomise_mbuf_chain(struct mbuf *m)
147303980Sngie{
148303980Sngie	int i, data, len;
149303980Sngie
150303980Sngie	for (i = 0; i < m->m_len; i += sizeof(int)) {
151303980Sngie		data = rand();
152303980Sngie		if (i + sizeof(int) < (size_t)m->m_len)
153303980Sngie			len = sizeof(int);
154303980Sngie		else
155303980Sngie			len = m->m_len - i;
156303980Sngie		memcpy(m->m_data + i, &data, len);
157303980Sngie	}
158303980Sngie	if (m->m_next)
159303980Sngie		randomise_mbuf_chain(m->m_next);
160303980Sngie}
161303980Sngie
162303980Sngiestatic int
163303980Sngiembuf_len(struct mbuf *m)
164303980Sngie{
165303980Sngie	return m == NULL ? 0 : m->m_len + mbuf_len(m->m_next);
166303980Sngie}
167303980Sngie
168303980Sngieint	in_cksum_portable(struct mbuf *, int);
169303980Sngieint	in_cksum(struct mbuf *, int);
170303980Sngie
171303980Sngieint
172303980Sngiemain(int argc, char **argv)
173303980Sngie{
174303980Sngie	struct rusage res;
175303980Sngie	struct timeval tv, old_tv;
176303980Sngie	int loops, old_sum, off, len;
177303980Sngie#ifdef HAVE_CPU_IN_CKSUM
178303980Sngie	int new_sum;
179303980Sngie#endif
180303980Sngie	long i, iterations;
181303980Sngie	uint32_t init_sum;
182303980Sngie	struct mbuf *m;
183303980Sngie	bool verbose;
184303980Sngie	int c;
185303980Sngie
186303980Sngie	loops = 16;
187303980Sngie	verbose = false;
188303980Sngie	random_aligned = 0;
189303980Sngie	iterations = 100000;
190303980Sngie
191303980Sngie	while ((c = getopt(argc, argv, "i:l:u:v")) != -1) {
192303980Sngie		switch (c) {
193303980Sngie		case 'i':
194303980Sngie			iterations = atoi(optarg);
195303980Sngie			break;
196303980Sngie		case 'l':
197303980Sngie			loops = atoi(optarg);
198303980Sngie			break;
199303980Sngie		case 'u':
200303980Sngie			random_aligned = atoi(optarg);
201303980Sngie			break;
202303980Sngie		case 'v':
203303980Sngie			verbose = true;
204303980Sngie			break;
205303980Sngie		default:
206303980Sngie			errx(1, "%s [-l <loops>] [-u <unalign> [-i <iterations> "
207303980Sngie			    "[<mbuf-size> ...]", getprogname());
208303980Sngie		}
209303980Sngie	}
210303980Sngie
211303980Sngie	for (; loops; --loops) {
212303980Sngie		if ((m = allocate_mbuf_chain(argv + 4)) == NULL)
213303980Sngie			continue;
214303980Sngie		randomise_mbuf_chain(m);
215303980Sngie		init_sum = rand();
216303980Sngie		len = mbuf_len(m);
217303980Sngie
218303980Sngie		/* force one loop over all data */
219303980Sngie		if (loops == 1)
220303980Sngie			off = 0;
221303980Sngie		else
222303980Sngie			off = len ? rand() % len : 0;
223303980Sngie
224303980Sngie		len -= off;
225303980Sngie		old_sum = portable_cpu_in_cksum(m, len, off, init_sum);
226303980Sngie#ifdef HAVE_CPU_IN_CKSUM
227303980Sngie#ifdef MBUFDUMP
228303980Sngie		printf("m->m_len=%d len=%d off=%d\n", m->m_len, len, off);
229303980Sngie		dump_mbuf(m, len, off);
230303980Sngie#endif
231303980Sngie		new_sum = cpu_in_cksum(m, len, off, init_sum);
232303980Sngie		if (old_sum != new_sum)
233303980Sngie			errx(1, "comparison failed: %x %x", old_sum, new_sum);
234303980Sngie#else
235303980Sngie		__USE(old_sum);
236303980Sngie#endif
237303980Sngie
238303980Sngie		if (iterations == 0)
239303980Sngie			continue;
240303980Sngie
241303980Sngie		getrusage(RUSAGE_SELF, &res);
242303980Sngie		tv = res.ru_utime;
243303980Sngie		for (i = iterations; i; --i)
244303980Sngie			(void)portable_cpu_in_cksum(m, len, off, init_sum);
245303980Sngie		getrusage(RUSAGE_SELF, &res);
246303980Sngie		timersub(&res.ru_utime, &tv, &old_tv);
247303980Sngie		if (verbose)
248303980Sngie			printf("portable version: %jd.%06jd\n",
249303980Sngie			    (intmax_t)old_tv.tv_sec, (intmax_t)old_tv.tv_usec);
250303980Sngie
251303980Sngie#ifdef HAVE_CPU_IN_CKSUM
252303980Sngie		getrusage(RUSAGE_SELF, &res);
253303980Sngie		tv = res.ru_utime;
254303980Sngie		for (i = iterations; i; --i)
255303980Sngie			(void)cpu_in_cksum(m, len, off, init_sum);
256303980Sngie		getrusage(RUSAGE_SELF, &res);
257303980Sngie		timersub(&res.ru_utime, &tv, &tv);
258303980Sngie		if (verbose) {
259303980Sngie			printf("test version:     %jd.%06jd\n",
260303980Sngie			    (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec);
261303980Sngie			printf("relative time:    %3.g%%\n",
262303980Sngie			    100 * ((double)tv.tv_sec * 1e6 + tv.tv_usec) /
263303980Sngie			    ((double)old_tv.tv_sec * 1e6 + old_tv.tv_usec + 1));
264303980Sngie		}
265303980Sngie#endif
266303980Sngie		free_mbuf_chain(m);
267303980Sngie	}
268303980Sngie
269303980Sngie	return 0;
270303980Sngie}
271