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