diff -Naur como-0.4/base/sniffer-sk98.c como-0.4.fix1/base/sniffer-sk98.c --- como-0.4/base/sniffer-sk98.c 2005-06-14 13:39:11.000000000 +0100 +++ como-0.4.fix1/base/sniffer-sk98.c 2005-08-12 10:45:19.224778379 +0100 @@ -25,9 +25,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sniffer-sk98.c,v 1.6 2005/06/14 12:39:11 iannak1 Exp $ + * $Id: sniffer-sk98.c,v 1.13 2005/07/13 15:37:20 sos22 Exp $ */ +#include #include #include #include @@ -38,6 +39,7 @@ #include "como.h" #include "sniffers.h" #include "sk98_timers.h" +#include "sk98_uspace_if.h" /* * SNIFFER --- SysKonnect card SK98 @@ -58,54 +60,21 @@ /* - * Rings with packet tokens. Modified by kernel and user - */ -#define RING_SIZE 65535 -struct map_area_header { - /* Stuff mostly written by userspace */ - unsigned k2u_cons; - unsigned u2k_prod; - unsigned u2k_tokens[RING_SIZE]; - - /* Stuff mostly written by kernel */ - unsigned u2k_cons; - unsigned k2u_prod; - struct { - unsigned token; - unsigned tstamp; - unsigned short len; - unsigned short interface; - } k2u_pipe[RING_SIZE]; -}; - -#define mb() asm volatile("lock; addl $0, (%%esp)" ::: "memory") - - -/* - * IOCTL structure used to pass info to the driver - */ -struct sk98_ioctl_map { - void *start_addr; - unsigned long len; - unsigned offset; -}; -#define SK98_IOCTL_MAP 1 - - -/* * Sniffer state variables for SK98 card (include packets, tokens * and time-synchronization information). */ struct _snifferinfo { - struct map_area_header * m; + struct sk98_map_area_header * m; struct packet_data_area * packet_pool; unsigned retimer_size; clock_retimer_t ** clock_retimers; - int tokens[RING_SIZE]; + int tokens[SK98_RING_SIZE]; int no_tokens; }; +#define mb() asm volatile("lock; addl $0, 0(%%esp)\n" ::: "memory") + /* * -- discard_packets * @@ -113,12 +82,12 @@ * */ static void -discard_packets(struct map_area_header * m) +discard_packets(struct sk98_map_area_header * m) { /* Return packets to the OS without examining them */ - while (m->k2u_prod > m->k2u_cons) { - m->u2k_tokens[m->u2k_prod % RING_SIZE] = - m->k2u_pipe[m->k2u_cons % RING_SIZE].token; + while (m->k2u_prod != m->k2u_cons) { + m->u2k_tokens[m->u2k_prod % SK98_RING_SIZE] = + m->k2u_pipe[m->k2u_cons % SK98_RING_SIZE].token; mb(); m->u2k_prod++; m->k2u_cons++; @@ -136,7 +105,7 @@ void calibrate(struct _snifferinfo * info) { - struct map_area_header * m = info->m; + struct sk98_map_area_header * m = info->m; clock_retimer_t ** cr = info->clock_retimers; uint size = info->retimer_size; uint num; @@ -149,17 +118,18 @@ struct timeval now; uint s, t; - while (m->k2u_cons >= m->k2u_prod) + discard_packets(m); + while (m->k2u_cons == m->k2u_prod) mb(); t = m->k2u_prod; mb(); gettimeofday(&now, NULL); - for (s = m->k2u_cons; s < t; s++) { + for (s = m->k2u_cons; s != t; s++) { uint iface; int ind; - ind = s % RING_SIZE; + ind = s % SK98_RING_SIZE; iface = m->k2u_pipe[ind].interface; if (iface == (unsigned short)-1) continue; @@ -174,13 +144,12 @@ if (cr[iface] == NULL) { logmsg(V_LOGSNIFFER, "Found interface %d\n", iface); - cr[iface] = new_clock_retimer("", 0); + cr[iface] = new_clock_retimer("", iface); num++; } - calibrated += doTimer(cr[iface], m->k2u_pipe[ind].tstamp, 0, &now); + calibrated += doTimer(cr[iface], m->k2u_pipe[ind].tstamp, &now); } - discard_packets(m); - } while (calibrated != num); + } while (num != calibrated); info->retimer_size = size; info->clock_retimers = cr; @@ -208,9 +177,12 @@ /* Start up the timestamps library * - * XXX where do we get 78110207 from? (initial frequency?) + * 78110207 is an initial frequency estimate from the card's data + * sheet, in Hz. There are also some cards in existence which + * need about half this; in that case, timer calibration may take + * a little longer but it should still work. */ - initialise_timestamps(1, 78110207, NULL); + initialise_timestamps(31250000); /* open the device */ fd = open(src->device, O_RDWR); @@ -227,7 +199,7 @@ * mmap the region that contains the ring buffers * with the tokens. */ - info->m = mmap(NULL, sizeof(struct map_area_header), + info->m = mmap(NULL, sizeof(struct sk98_map_area_header), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (info->m == MAP_FAILED) { logmsg(LOGWARN, "sniffer-sk98: failed to mmap %s: %s\n", @@ -238,7 +210,8 @@ /* inform the driver of where the packets should go */ args.len = 1024 * 1024 * BUFFER_MB; - args.offset = 0; + args.offset = 24; + args.version = SK98_CURRENT_VERSION; info->packet_pool = safe_malloc(args.len); args.start_addr = info->packet_pool; if (ioctl(fd, SK98_IOCTL_MAP, &args) < 0) { @@ -249,14 +222,18 @@ } /* we have no packets */ - info->no_tokens = -1; + info->no_tokens = 0; + logmsg(LOGSNIFFER, "starting sk98 timer calibration...\n"); /* do timer calibration */ calibrate(info); + logmsg(LOGSNIFFER, "done sk98 timer calibration.\n"); + + discard_packets(info->m); src->fd = fd; - src->flags = SNIFF_POLL; - src->polling = TIME2TS(0, 1000); + src->flags = SNIFF_SELECT; + src->polling = 0; return 0; /* success */ } @@ -267,10 +244,10 @@ * gives token back to kernel */ static void -return_token(struct map_area_header * m, unsigned token) +return_token(struct sk98_map_area_header * m, unsigned token) { unsigned ind; - ind = m->u2k_prod % RING_SIZE; + ind = m->u2k_prod % SK98_RING_SIZE; m->u2k_tokens[ind] = token; mb(); m->u2k_prod++; @@ -289,14 +266,30 @@ struct _snifferinfo * info = (struct _snifferinfo *) src->ptr; pkt_t * pkt; int npkts; /* processed pkts */ + unsigned pending; + static unsigned max_pending; + static unsigned last_drop; + int x; + unsigned new_drop; /* return all tokens of previous round */ - for (; info->no_tokens >= 0; info->no_tokens--) - return_token(info->m, info->tokens[info->no_tokens]); - - info->no_tokens = 0; - - for (npkts = 0, pkt = out; npkts < max_no; npkts++, pkt++) { + mb(); + for (x = 0; x < info->no_tokens; x++) + if (info->tokens[x] != -1) + return_token(info->m, info->tokens[x]); + info->no_tokens = 0; + + npkts = 0; + pkt = out; + last_drop = new_drop; + + pending = info->m->k2u_prod - info->m->k2u_cons; + if (pending > max_pending) + max_pending = pending; + rlimit_logmsg(1000, LOGSNIFFER, + "Current ring fullness %d, max %d, drop %d.\n", + pending, max_pending, info->m->drop_counter); + for (; npkts < max_no; npkts++, pkt++) { uint ind; uint token; ushort iface; @@ -305,22 +298,27 @@ if (info->m->k2u_cons == info->m->k2u_prod) break; /* no more tokens */ mb(); - ind = info->m->k2u_cons % RING_SIZE; + ind = info->m->k2u_cons % SK98_RING_SIZE; token = info->m->k2u_pipe[ind].token; iface = info->m->k2u_pipe[ind].interface; if (iface == (ushort)-1) { /* Kernel decided not to use this token. Return it. */ - return_token(info->m, token); + mb(); info->m->k2u_cons++; + mb(); + return_token(info->m, token); + info->no_tokens = npkts; return npkts; } if (iface >= info->retimer_size || info->clock_retimers[iface] == NULL){ /* Clock calibration was incomplete. Uh oh. */ logmsg(LOGWARN, "calibration incomplete, returning token\n"); - return_token(info->m, token); + mb(); info->m->k2u_cons++; + mb(); + return_token(info->m, token); return -1; } @@ -337,7 +335,8 @@ * update layer2 information and offsets of layer 3 and above. * this sniffer only runs on ethernet frames. */ - updateofs(pkt, COMOTYPE_ETH); + updateofs(pkt, COMOTYPE_ETH); + mb(); info->m->k2u_cons++; } @@ -351,7 +350,7 @@ { struct _snifferinfo * info = (struct _snifferinfo *) src->ptr; - munmap(info->m, sizeof(struct map_area_header)); + munmap(info->m, sizeof(struct sk98_map_area_header)); free(info->packet_pool); free(src->ptr); } diff -Naur como-0.4/extra/sk98_timers.c como-0.4.fix1/extra/sk98_timers.c --- como-0.4/extra/sk98_timers.c 2005-06-01 18:19:04.000000000 +0100 +++ como-0.4.fix1/extra/sk98_timers.c 2005-08-11 16:40:28.000000000 +0100 @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sk98_timers.c,v 1.1 2005/06/01 17:19:04 iannak1 Exp $ + * $Id: sk98_timers.c,v 1.3 2005/07/06 12:22:26 sos22 Exp $ */ #include @@ -101,52 +101,17 @@ final answer, but we can use them to make initial estimates for the next phase. */ + unsigned long tstamp_freq; }; static unsigned long drift_period = 1500000; // min= 48ms, max=0.432s -static unsigned long nictstamp_freq = 31250000; - -static int do_clock_retime; -static FILE *drift_file; +static unsigned long def_nictstamp_freq = 312500000; /*************************************************************************/ -static void record_tstamp_drift_file(unsigned long nictstamp, - struct timeval *now, - unsigned total_pkts, - unsigned dev_num) -{ - unsigned long data[5]; - if(drift_file) { - data[0] = nictstamp; - data[1] = (unsigned long) now->tv_sec; - data[2] = (unsigned long) now->tv_usec; - data[3] = total_pkts; - data[4] = dev_num; - fwrite(data, sizeof(unsigned long), 5, drift_file); - fflush(drift_file); - } -} - -static void record_endrec_drift_file(struct timeval *timebase, - unsigned dev_num) -{ - unsigned long data[5]; - if(drift_file) - { - data[0] = 0; - data[1] = (unsigned long) timebase->tv_sec; - data[2] = (unsigned long) timebase->tv_usec; - data[3] = 0; - data[4] = dev_num; - fwrite(data, sizeof(unsigned long), 5, drift_file); - fflush(drift_file); - } -} - /* Is x >= y, allowing for overflow? */ #define TSTAMP_GREATEREQ(x, y) \ ( (x) >= (y) ? ((x) - (y) < 1 << 30) : ((y) - (x) > 1 << 30) ) @@ -209,6 +174,7 @@ err(1, "allocating timer recalibration structure"); work->name = strdup(name); work->dev_num = dev_num; + work->tstamp_freq = def_nictstamp_freq; return work; } @@ -219,7 +185,7 @@ Returns 1 if we just went from an uncalibrated to a calibrated state. */ int doTimer(clock_retimer_t *timer, unsigned long nictstamp, - unsigned total_pkts, struct timeval *now) + struct timeval *now) { struct timeval est_time; /* Estimated packet arrival time */ double timed; /* Difference between est_time and time, seconds */ @@ -239,14 +205,16 @@ if (timer->mode == clock_mode_prestart) { reset_timer(timer, nictstamp, now); - if(do_clock_retime) - timer->mode = clock_mode_find_intercept; - else - timer->mode = clock_mode_constant_output; + timer->mode = clock_mode_find_intercept; timer->samples_bad = 0; return 0; } + if (timer->mode == clock_mode_constant_output) { + /* That's all we need to do for now. */ + return 0; + } + if (!TSTAMP_GREATEREQ(nictstamp, timer->nextdrift)) { /* It's too early to do the next phase. */ return 0; @@ -254,13 +222,6 @@ timer->nextdrift += drift_interval(); - record_tstamp_drift_file(nictstamp, now, total_pkts, timer->dev_num); - - if (timer->mode == clock_mode_constant_output) { - /* That's all we need to do for now. */ - return 0; - } - getTime(timer, nictstamp, &est_time, NULL); timed = tv_to_secs(&est_time) - tv_to_secs(now); @@ -307,7 +268,6 @@ return 0; } - /* Interesting times: -- We start a calibration run, system clock (A) @@ -347,11 +307,11 @@ s2_r = s_yy - (grad * grad * s_xx) / (timer->samples - 2); uncerc2 = s2_r * (1 + 1.0 / timer->samples + m_x * m_x / s_xx); - logmsg(LOGCAPTURE, "Interface %d: timer uncerc %e, grad %e.\n", - timer->dev_num, sqrt(uncerc2), grad); - /* Guess the nictstamp frequency from the data we've collected. */ - nictstamp_freq = ((1.0 + grad) * (double) nictstamp_freq)+0.5; + timer->tstamp_freq = ((1.0 + grad) * (double) timer->tstamp_freq)+0.5; + + logmsg(LOGSNIFFER, "Interface %d: timer uncerc %e, grad %e, freq %d.\n", + timer->dev_num, sqrt(uncerc2), grad, timer->tstamp_freq); if (grad > 1e-6 || grad < -1e-6 || timer->samples_bad) { /* We don't trust the calculated intercept if we've had to @@ -365,9 +325,10 @@ secs_to_tv(&timer->time_base, tv_to_secs(&timer->time_base) - inter); - record_endrec_drift_file(&timer->time_base, timer->dev_num); timer->mode = clock_mode_constant_output; + logmsg(LOGSNIFFER, "Interface %d: frequency estimate %d.\n", + timer->dev_num, timer->tstamp_freq); return 1; } @@ -397,9 +358,9 @@ that to be safe, so we have to fart about with fixed point arithmetic, like so. */ tics = timer->tic_cur - timer->tic_base; - t.tv_sec = tics / nictstamp_freq; - t.tv_nsec = (1000000000ull * (tics % nictstamp_freq)) / - nictstamp_freq; + t.tv_sec = tics / timer->tstamp_freq; + t.tv_nsec = (1000000000ull * (tics % timer->tstamp_freq)) / + timer->tstamp_freq; assert(t.tv_nsec >= 0); assert(t.tv_nsec < 1000000000); @@ -448,21 +409,8 @@ return; } -void initialise_timestamps(unsigned do_retime, unsigned long initial_freq, - const char *drift_fname) +void initialise_timestamps(unsigned long initial_freq) { - char hostname[256]; - - if (!do_retime) - abort(); - do_clock_retime = do_retime; if (initial_freq != 0) - nictstamp_freq = initial_freq; - if (drift_fname != NULL) { - drift_file = fopen(drift_fname, "w"); - if (drift_file == NULL) - err(1, "openning drift file %s", drift_fname); - - gethostname(hostname, 256); - } + def_nictstamp_freq = initial_freq; } diff -Naur como-0.4/extra/sk98_timers.h como-0.4.fix1/extra/sk98_timers.h --- como-0.4/extra/sk98_timers.h 2005-06-01 18:19:04.000000000 +0100 +++ como-0.4.fix1/extra/sk98_timers.h 2005-08-11 16:40:28.000000000 +0100 @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sk98_timers.h,v 1.1 2005/06/01 17:19:04 iannak1 Exp $ + * $Id: sk98_timers.h,v 1.2 2005/06/23 11:43:59 sos22 Exp $ */ @@ -37,10 +37,8 @@ void getTime(clock_retimer_t *timer, unsigned long nictstamp, struct timeval *tv, struct timespec *ts); int doTimer(clock_retimer_t *timer, unsigned long nictstamp, - unsigned total_pkts, struct timeval *now); + struct timeval *now); clock_retimer_t *new_clock_retimer(const char *name, unsigned dev_num); -void initialise_timestamps(unsigned do_clock_retime, - unsigned long initial_freq, - const char *drift_fname); +void initialise_timestamps(unsigned long initial_freq); diff -Naur como-0.4/include/sk98_uspace_if.h como-0.4.fix1/include/sk98_uspace_if.h --- como-0.4/include/sk98_uspace_if.h 1970-01-01 01:00:00.000000000 +0100 +++ como-0.4.fix1/include/sk98_uspace_if.h 2005-08-11 16:40:28.000000000 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 Intel Corporation + * Copyright (c) 2005 Steven Smith, University of Cambridge Computer Laboratory. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sk98_uspace_if.h,v 1.1 2005/06/20 13:40:00 sos22 Exp $ + */ + +/* Can't cope with any packets bigger than this. This must be a + factor of the page size. */ +#define SK98_EXPECTED_PACKET_SIZE 2048 + +#define SK98_RING_SIZE 65534 +struct sk98_map_area_header { + /* Stuff mostly written by userspace */ + unsigned k2u_cons; + unsigned u2k_prod; + unsigned u2k_tokens[SK98_RING_SIZE]; + + /* Stuff mostly written by kernel space */ + unsigned u2k_cons; + unsigned k2u_prod; + struct { + unsigned token; + unsigned tstamp; + unsigned short len; + unsigned short interface; + } k2u_pipe[SK98_RING_SIZE]; + + unsigned drop_counter; +}; + +struct sk98_ioctl_map { + void *start_addr; + unsigned long len; + unsigned offset; + unsigned version; +#define SK98_CURRENT_VERSION 4 +}; +#define SK98_IOCTL_MAP 1 +