Index: share/man/man4/bpf.4 =================================================================== --- share/man/man4/bpf.4 (revision 228435) +++ share/man/man4/bpf.4 (working copy) @@ -49,7 +49,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 15, 2010 +.Dd December 15, 2011 .Dt BPF 4 .Os .Sh NAME @@ -516,7 +516,26 @@ .It Dv BIOCSTSTAMP .It Dv BIOCGTSTAMP .Pq Li u_int -Set or get format and resolution of the time stamps returned by BPF. +Set or get the format, resolution and source of time stamps returned by BPF. +Note that the +.Dv BPF_T_FBCLOCK , +.Dv BPF_T_FBCLOCK_FAST , +.Dv BPF_T_FBCLOCK_MONOTONIC , +.Dv BPF_T_FBCLOCK_MONOTONIC_FAST , +.Dv BPF_T_FFCLOCK , +.Dv BPF_T_FFCLOCK_FAST , +.Dv BPF_T_FFCLOCK_MONOTONIC , +.Dv BPF_T_FFCLOCK_MONOTONIC_FAST , +and +.Dv BPF_T_FFCOUNTER +options described below are not allowed unless the kernel has been compiled +with feed-forward clock support +.Po +see +.Xr ffclock 4 +for more details +.Pc . +.Pp Set to .Dv BPF_T_MICROTIME , .Dv BPF_T_MICROTIME_FAST , @@ -545,32 +564,58 @@ .Vt struct bintime format. Set to +.Dv BPF_T_FBCLOCK , +.Dv BPF_T_FBCLOCK_FAST , +.Dv BPF_T_FBCLOCK_MONOTONIC_FAST , +.Dv BPF_T_FFCLOCK , +.Dv BPF_T_FFCLOCK_FAST , +or +.Dv BPF_T_FFCLOCK_MONOTONIC_FAST +to specify that the BPF device should explicitly use the feedback or +feed-forward clock respectively for time stamp generation. +Set to +.Dv BPF_T_FFCOUNTER +to get a 64-bit feed-forward counter value. +Set to .Dv BPF_T_NONE to ignore time stamp. +By default, time stamps are derived from the active system clock +.Po +feedback or +feed-forward +.Pc +and initilized to +.Dv BPF_T_MICROTIME . +.Pp All 64-bit time stamp formats are wrapped in .Vt struct bpf_ts . The .Dv BPF_T_MICROTIME_FAST , .Dv BPF_T_NANOTIME_FAST , .Dv BPF_T_BINTIME_FAST , +.Dv BPF_T_FBCLOCK_FAST , +.Dv BPF_T_FFCLOCK_FAST , .Dv BPF_T_MICROTIME_MONOTONIC_FAST , .Dv BPF_T_NANOTIME_MONOTONIC_FAST , +.Dv BPF_T_BINTIME_MONOTONIC_FAST , +.Dv BPF_T_FBCLOCK_MONOTONIC_FAST , and -.Dv BPF_T_BINTIME_MONOTONIC_FAST +.Dv BPF_T_FFCLOCK_MONOTONIC_FAST are analogs of corresponding formats without _FAST suffix but do not perform a full time counter query, so their accuracy is one timer tick. The .Dv BPF_T_MICROTIME_MONOTONIC , .Dv BPF_T_NANOTIME_MONOTONIC , .Dv BPF_T_BINTIME_MONOTONIC , +.Dv BPF_T_FBCLOCK_MONOTONIC , +.Dv BPF_T_FFCLOCK_MONOTONIC , .Dv BPF_T_MICROTIME_MONOTONIC_FAST , .Dv BPF_T_NANOTIME_MONOTONIC_FAST , +.Dv BPF_T_BINTIME_MONOTONIC_FAST , +.Dv BPF_T_FBCLOCK_MONOTONIC_FAST , and -.Dv BPF_T_BINTIME_MONOTONIC_FAST +.Dv BPF_T_FFCLOCK_MONOTONIC_FAST store the time elapsed since kernel boot. -This setting is initialized to -.Dv BPF_T_MICROTIME -by default. .It Dv BIOCFEEDBACK .Pq Li u_int Set packet feedback mode. @@ -1021,6 +1066,7 @@ .Xr poll 2 , .Xr select 2 , .Xr byteorder 3 , +.Xr ffclock 4 , .Xr ng_bpf 4 , .Xr bpf 9 .Rs Index: sys/sys/timeffc.h =================================================================== --- sys/sys/timeffc.h (revision 228435) +++ sys/sys/timeffc.h (working copy) @@ -81,20 +81,76 @@ #define FFCLOCK_STA_WARMUP 2 /* - * Clock flags to select how the feed-forward counter is converted to absolute - * time by ffclock_convert_abs(). - * FAST: do not read the hardware counter, return feed-forward clock time - * at last tick. The time returned has the resolution of the kernel - * tick (1/hz [s]). - * LERP: linear interpolation of ffclock time to guarantee monotonic time. - * LEAPSEC: include leap seconds. - * UPTIME: removes time of boot. + * Flags for use predominantly by sysclock_getsnapshot() to control how the + * timecounter hardware is read and how the hardware snapshot is converted into + * absolute time. + * {FB|FF}CLOCK_FAST: Do not read the hardware counter, instead using the + * value at last tick. The time returned has a resolution + * of the kernel tick timer (1/hz [s]). + * FFCLOCK_LERP: Linear interpolation of ffclock time to guarantee + * monotonic time. + * FFCLOCK_LEAPSEC: Include leap seconds. + * {FB|FF}CLOCK_UPTIME: Time stamp should be relative to system boot, not epoch. */ -#define FFCLOCK_FAST 1 -#define FFCLOCK_LERP 2 -#define FFCLOCK_LEAPSEC 4 -#define FFCLOCK_UPTIME 8 +#define FFCLOCK_FAST 0x00000001 +#define FFCLOCK_LERP 0x00000002 +#define FFCLOCK_LEAPSEC 0x00000004 +#define FFCLOCK_UPTIME 0x00000008 +#define FFCLOCK_MASK 0x0000ffff +#define FBCLOCK_FAST 0x00010000 +#define FBCLOCK_UPTIME 0x00020000 +#define FBCLOCK_MASK 0xffff0000 + +/* + * Feedback clock specific info structure. The feedback clock's estimation of + * clock error is an absolute figure determined by the NTP algorithm. The status + * is determined by the userland daemon. + */ +struct fbclock_info { + struct bintime error; + struct bintime tick_time; + uint64_t th_scale; + int status; +}; + +/* + * Feed-forward clock specific info structure. The feed-forward clock's + * estimation of clock error is an upper bound, which although potentially + * looser than the feedback clock equivalent, is much more reliable. The status + * is determined by the userland daemon. + */ +struct ffclock_info { + struct bintime error; + struct bintime tick_time; + struct bintime tick_time_lerp; + uint64_t period; + uint64_t period_lerp; + int leapsec_adjustment; + int status; +}; + +/* + * Snapshot of system clocks and related information. Holds time read from each + * clock based on a single read of the active hardware timecounter, as well as + * respective clock information such as error estimates and the ffcounter value + * at the time of the read. + */ +struct sysclock_snap { + struct fbclock_info fb_info; + struct ffclock_info ff_info; + ffcounter ffcount; + unsigned int delta; + int sysclock_active; +}; + +/* Take a snapshot of the system clocks and related information. */ +void sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast); + +/* Convert a timestamp from the selected system clock into bintime. */ +int sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, + uint32_t sysclock_flags); + /* Resets feed-forward clock from RTC */ void ffclock_reset_clock(struct timespec *ts); Index: sys/kern/kern_ntptime.c =================================================================== --- sys/kern/kern_ntptime.c (revision 228435) +++ sys/kern/kern_ntptime.c (working copy) @@ -148,13 +148,13 @@ #define SHIFT_FLL 2 /* FLL loop gain (shift) */ static int time_state = TIME_OK; /* clock state */ -static int time_status = STA_UNSYNC; /* clock status bits */ +int time_status = STA_UNSYNC; /* clock status bits */ static long time_tai; /* TAI offset (s) */ static long time_monitor; /* last time offset scaled (ns) */ static long time_constant; /* poll interval (shift) (s) */ static long time_precision = 1; /* clock precision (ns) */ static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */ -static long time_esterror = MAXPHASE / 1000; /* estimated error (us) */ +long time_esterror = MAXPHASE / 1000; /* estimated error (us) */ static long time_reftime; /* time at last adjustment (s) */ static l_fp time_offset; /* time offset (ns) */ static l_fp time_freq; /* frequency offset (ns/s) */ Index: sys/kern/kern_tc.c =================================================================== --- sys/kern/kern_tc.c (revision 228435) +++ sys/kern/kern_tc.c (working copy) @@ -28,9 +28,7 @@ #include #include #include -#ifdef FFCLOCK #include -#endif #include #include #include @@ -454,15 +452,6 @@ #endif /* FFCLOCK */ #ifdef FFCLOCK -/* - * Support for feed-forward synchronization algorithms. This is heavily inspired - * by the timehands mechanism but kept independent from it. *_windup() functions - * have some connection to avoid accessing the timecounter hardware more than - * necessary. - */ - -int sysclock_active = SYSCLOCK_FBCK; - /* Feed-forward clock estimates kept updated by the synchronization daemon. */ struct ffclock_estimate ffclock_estimate; struct bintime ffclock_boottime; /* Feed-forward boot time estimate. */ @@ -956,9 +945,143 @@ getmicrouptime_fromclock(tvp, sysclock_active); } + #endif /* FFCLOCK */ /* + * Support for feed-forward synchronization algorithms. This is heavily inspired + * by the timehands mechanism but kept independent from it. *_windup() functions + * have some connection to avoid accessing the timecounter hardware more than + * necessary. + */ + +int sysclock_active = SYSCLOCK_FBCK; + +/* Internal NTP status and error estimates. */ +extern int time_status; +extern long time_esterror; + +void +sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast) +{ + struct fbclock_info *fbi; + struct timehands *th; + struct bintime bt; + unsigned int delta, gen; +#ifdef FFCLOCK + ffcounter ffcount; + struct fftimehands *ffth; + struct ffclock_info *ffi; + struct ffclock_estimate cest; + + ffi = &clock_snap->ff_info; +#endif + + fbi = &clock_snap->fb_info; + delta = 0; + + do { + th = timehands; + gen = th->th_generation; + fbi->th_scale = th->th_scale; + fbi->tick_time = th->th_offset; +#ifdef FFCLOCK + ffth = fftimehands; + ffi->tick_time = ffth->tick_time_lerp; + ffi->tick_time_lerp = ffth->tick_time_lerp; + ffi->period = ffth->cest.period; + ffi->period_lerp = ffth->period_lerp; + clock_snap->ffcount = ffth->tick_ffcount; + cest = ffth->cest; +#endif + if (!fast) + delta = tc_delta(th); + } while (gen == 0 || gen != th->th_generation); + + clock_snap->delta = delta; + clock_snap->sysclock_active = sysclock_active; + + /* Record feedback clock status and error. */ + clock_snap->fb_info.status = time_status; + /* XXX: Very crude estimate of feedback clock error. */ + bt.sec = time_esterror / 1000000; + bt.frac = ((time_esterror - bt.sec) * 1000000) * + (uint64_t)18446744073709ULL; + clock_snap->fb_info.error = bt; + +#ifdef FFCLOCK + if (!fast) + clock_snap->ffcount += delta; + /* Record feed-forward clock leap second adjustment. */ + ffi->leapsec_adjustment = cest.leapsec_total; + if (clock_snap->ffcount > cest.leapsec_next) + ffi->leapsec_adjustment -= cest.leapsec; + + /* Record feed-forward clock status and error. */ + clock_snap->ff_info.status = cest.status; + ffcount = clock_snap->ffcount - cest.update_ffcount; + ffclock_convert_delta(ffcount, cest.period, &bt); + /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s]. */ + bintime_mul(&bt, cest.errb_rate * (uint64_t)18446744073709LL); + /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns]. */ + bintime_addx(&bt, cest.errb_abs * (uint64_t)18446744073LL); + clock_snap->ff_info.error = bt; +#endif +} + +int +sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, + uint32_t sysclock_flags) +{ +#ifdef FFCLOCK + struct bintime bt2; + uint64_t period; +#endif + + /* Fill a single struct bintime, make sure the flags make sense */ + if ((sysclock_flags & FFCLOCK_MASK) && (sysclock_flags & FBCLOCK_MASK)) + return (1); + + if (sysclock_flags & FBCLOCK_MASK) { + *bt = cs->fb_info.tick_time; + + if ((sysclock_flags & FBCLOCK_FAST) == 0) + bintime_addx(bt, cs->fb_info.th_scale * cs->delta); + + if ((sysclock_flags & FBCLOCK_UPTIME) == 0) + bintime_add(bt, &boottimebin); + } + +#ifdef FFCLOCK + if (sysclock_flags & FFCLOCK_MASK) { + + if (sysclock_flags & FFCLOCK_LERP) { + *bt = cs->ff_info.tick_time_lerp; + period = cs->ff_info.period_lerp; + } else { + *bt = cs->ff_info.tick_time; + period = cs->ff_info.period; + } + + if ((sysclock_flags & FFCLOCK_FAST) == 0) { + ffclock_convert_delta(cs->delta, period, &bt2); + bintime_add(bt, &bt2); + } + + /* Leap second adjustment. */ + if (sysclock_flags & FFCLOCK_LEAPSEC) + bt->sec -= cs->ff_info.leapsec_adjustment; + + /* Boot time adjustment, for uptime/monotonic clocks. */ + if (sysclock_flags & FFCLOCK_UPTIME) + bintime_sub(bt, &ffclock_boottime); + } +#endif + + return (0); +} + +/* * Initialize a new timecounter and possibly use it. */ void Index: sys/net/bpf.c =================================================================== --- sys/net/bpf.c (revision 228435) +++ sys/net/bpf.c (working copy) @@ -1,12 +1,17 @@ /*- * Copyright (c) 1990, 1991, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. + * Copyright (c) 2011 The University of Melbourne. + * All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * + * Portions of this software were developed by Julien Ridoux at the University + * of Melbourne under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,6 +44,7 @@ #include "opt_bpf.h" #include "opt_compat.h" +#include "opt_ffclock.h" #include "opt_netgraph.h" #include @@ -55,6 +61,7 @@ #include #include #include +#include #include #include @@ -112,7 +119,7 @@ uint16_t bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; -#endif +#endif /* !BURN_BRIDGES */ struct bpf_program32 { u_int bf_len; @@ -130,9 +137,44 @@ #define BIOCGDLTLIST32 _IOWR('B', 121, struct bpf_dltlist32) #define BIOCSETWF32 _IOW('B', 123, struct bpf_program32) #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) -#endif +#endif /* COMPAT_FREEBSD32 */ /* + * Safety belt to ensure ABI of structs bpf_hdr32, bpf_hdr and bpf_xhdr are + * preserved for use with FFCLOCK, which changes the stamp field in the + * structs to allow storing a regular time stamp or ffcounter stamp. + */ +CTASSERT(sizeof(struct bpf_ts) >= sizeof(ffcounter) && + sizeof(struct bintime) >= sizeof(ffcounter)); + +static const char *bpftstypes[] = { + "none", +#define BPF_TSTAMP_NONE 0 + "fast", +#define BPF_TSTAMP_FAST 1 + "normal", +#define BPF_TSTAMP_NORMAL 2 + "external" +#define BPF_TSTAMP_EXTERNAL 3 +}; +#define NUM_BPFTSTYPES (sizeof(bpftstypes) / sizeof(*bpftstypes)) + +#define SET_CLOCKCFG_FLAGS(tstype, active, flags) do { \ + (flags) = 0; \ + if (BPF_T_CLOCK((tstype)) == BPF_T_SYSCLOCK && \ + active == SYSCLOCK_FBCK && ((tstype) & BPF_T_MONOTONIC)) \ + (flags) |= FBCLOCK_UPTIME; \ + else if ((BPF_T_CLOCK((tstype)) == BPF_T_SYSCLOCK && \ + active == SYSCLOCK_FFWD) || ((tstype) & BPF_T_FFCLOCK)) { \ + (flags) |= FFCLOCK_LERP; \ + if ((tstype) & BPF_T_MONOTONIC) \ + (flags) |= FFCLOCK_UPTIME; \ + else \ + (flags) |= FFCLOCK_LEAPSEC; \ + } \ +} while (0) + +/* * bpf_iflist is a list of BPF interface structures, each corresponding to a * specific DLT. The same network interface might have several BPF interface * structures registered by different layers in the stack (i.e., 802.11 @@ -172,6 +214,8 @@ &bpf_zerocopy_enable, 0, "Enable new zero-copy BPF buffer sessions"); static SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_MPSAFE | CTLFLAG_RW, bpf_stats_sysctl, "bpf statistics portal"); +static SYSCTL_NODE(_net_bpf, OID_AUTO, tscfg, CTLFLAG_RW, NULL, + "Per-interface timestamp configuration"); static d_open_t bpfopen; static d_read_t bpfread; @@ -1406,6 +1450,12 @@ u_int func; func = *(u_int *)addr; +#ifndef FFCLOCK + if (BPF_T_FORMAT(func) == BPF_T_FFCOUNTER || + BPF_T_CLOCK(func) != BPF_T_SYSCLOCK) { + error = EINVAL; + } else +#endif if (BPF_T_VALID(func)) d->bd_tstamp = func; else @@ -1759,48 +1809,6 @@ return (ready); } -#define BPF_TSTAMP_NONE 0 -#define BPF_TSTAMP_FAST 1 -#define BPF_TSTAMP_NORMAL 2 -#define BPF_TSTAMP_EXTERN 3 - -static int -bpf_ts_quality(int tstype) -{ - - if (tstype == BPF_T_NONE) - return (BPF_TSTAMP_NONE); - if ((tstype & BPF_T_FAST) != 0) - return (BPF_TSTAMP_FAST); - - return (BPF_TSTAMP_NORMAL); -} - -static int -bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) -{ - struct m_tag *tag; - int quality; - - quality = bpf_ts_quality(tstype); - if (quality == BPF_TSTAMP_NONE) - return (quality); - - if (m != NULL) { - tag = m_tag_locate(m, MTAG_BPF, MTAG_BPF_TIMESTAMP, NULL); - if (tag != NULL) { - *bt = *(struct bintime *)(tag + 1); - return (BPF_TSTAMP_EXTERN); - } - } - if (quality == BPF_TSTAMP_NORMAL) - binuptime(bt); - else - getbinuptime(bt); - - return (quality); -} - /* * Incoming linkage from device drivers. Process the packet pkt, of length * pktlen, which is stored in a contiguous buffer. The packet is parsed @@ -1811,14 +1819,19 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) { struct bintime bt; + struct sysclock_snap cs; struct bpf_d *d; + u_int clockflags, slen; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif - u_int slen; - int gottime; - gottime = BPF_TSTAMP_NONE; + if (bp->tstype == BPF_TSTAMP_NORMAL || bp->tstype == BPF_TSTAMP_FAST) + sysclock_getsnapshot(&cs, bp->tstype == BPF_TSTAMP_FAST ? + 1 : 0); + else + bzero(&bt, sizeof(bt)); + BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFD_LOCK(d); @@ -1838,8 +1851,17 @@ slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) { d->bd_fcount++; - if (gottime < bpf_ts_quality(d->bd_tstamp)) - gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); +#ifdef FFCLOCK + if (BPF_T_FORMAT(d->bd_tstamp) == BPF_T_FFCOUNTER) + bcopy(&bt, &cs.ffcount, sizeof(ffcounter)); + else +#endif + if (bp->tstype == BPF_TSTAMP_NORMAL || + bp->tstype == BPF_TSTAMP_FAST) { + SET_CLOCKCFG_FLAGS(d->bd_tstamp, + cs.sysclock_active, clockflags); + sysclock_snap2bintime(&cs, &bt, clockflags); + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif @@ -1862,12 +1884,12 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) { struct bintime bt; + struct sysclock_snap cs; struct bpf_d *d; + u_int clockflags, pktlen, slen; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif - u_int pktlen, slen; - int gottime; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1875,9 +1897,18 @@ return; } + if (bp->tstype == BPF_TSTAMP_NORMAL || bp->tstype == BPF_TSTAMP_FAST) + sysclock_getsnapshot(&cs, bp->tstype == BPF_TSTAMP_FAST ? + 1 : 0); +#ifdef notyet + else if (bp->tstype == BPF_TSTAMP_EXTERNAL) + /* XXX: Convert external tstamp to bintime. */ +#endif + else + bzero(&bt, sizeof(bt)); + pktlen = m_length(m, NULL); - gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) @@ -1894,8 +1925,17 @@ slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); if (slen != 0) { d->bd_fcount++; - if (gottime < bpf_ts_quality(d->bd_tstamp)) - gottime = bpf_gettime(&bt, d->bd_tstamp, m); +#ifdef FFCLOCK + if (BPF_T_FORMAT(d->bd_tstamp) == BPF_T_FFCOUNTER) + bcopy(&bt, &cs.ffcount, sizeof(ffcounter)); + else +#endif + if (bp->tstype == BPF_TSTAMP_NORMAL || + bp->tstype == BPF_TSTAMP_FAST) { + SET_CLOCKCFG_FLAGS(d->bd_tstamp, + cs.sysclock_active, clockflags); + sysclock_snap2bintime(&cs, &bt, clockflags); + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif @@ -1915,10 +1955,10 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) { struct bintime bt; + struct sysclock_snap cs; struct mbuf mb; struct bpf_d *d; - u_int pktlen, slen; - int gottime; + u_int clockflags, pktlen, slen; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1926,6 +1966,16 @@ return; } + if (bp->tstype == BPF_TSTAMP_NORMAL || bp->tstype == BPF_TSTAMP_FAST) + sysclock_getsnapshot(&cs, bp->tstype == BPF_TSTAMP_FAST ? + 1 : 0); +#ifdef notyet + else if (bp->tstype == BPF_TSTAMP_EXTERNAL) + /* XXX: Convert extern tstamp to bintime. */ +#endif + else + bzero(&bt, sizeof(bt)); + pktlen = m_length(m, NULL); /* * Craft on-stack mbuf suitable for passing to bpf_filter. @@ -1937,7 +1987,6 @@ mb.m_len = dlen; pktlen += dlen; - gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) @@ -1947,8 +1996,17 @@ slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); if (slen != 0) { d->bd_fcount++; - if (gottime < bpf_ts_quality(d->bd_tstamp)) - gottime = bpf_gettime(&bt, d->bd_tstamp, m); +#ifdef FFCLOCK + if (BPF_T_FORMAT(d->bd_tstamp) == BPF_T_FFCOUNTER) + bcopy(&bt, &cs.ffcount, sizeof(ffcounter)); + else +#endif + if (bp->tstype == BPF_TSTAMP_NORMAL || + bp->tstype == BPF_TSTAMP_FAST) { + SET_CLOCKCFG_FLAGS(d->bd_tstamp, + cs.sysclock_active, clockflags); + sysclock_snap2bintime(&cs, &bt, clockflags); + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif @@ -1962,11 +2020,6 @@ #undef BPF_CHECK_DIRECTION -#undef BPF_TSTAMP_NONE -#undef BPF_TSTAMP_FAST -#undef BPF_TSTAMP_NORMAL -#undef BPF_TSTAMP_EXTERN - static int bpf_hdrlen(struct bpf_d *d) { @@ -1998,15 +2051,9 @@ static void bpf_bintime2ts(struct bintime *bt, struct bpf_ts *ts, int tstype) { - struct bintime bt2; struct timeval tsm; struct timespec tsn; - if ((tstype & BPF_T_MONOTONIC) == 0) { - bt2 = *bt; - bintime_add(&bt2, &boottimebin); - bt = &bt2; - } switch (BPF_T_FORMAT(tstype)) { case BPF_T_MICROTIME: bintime2timeval(bt, &tsm); @@ -2153,8 +2200,16 @@ * move forward the length of the header plus padding. */ bzero(&hdr, sizeof(hdr)); - if (do_timestamp) - bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); + if (do_timestamp) { +#ifdef FFCLOCK + if (tstype & BPF_T_FFCOUNTER) + bcopy(bt, &hdr.bh_stamp.ffcount_stamp, + sizeof(ffcounter)); + else +#endif + bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); + } + hdr.bh_datalen = pktlen; hdr.bh_hdrlen = hdrlen; hdr.bh_caplen = caplen; @@ -2200,6 +2255,40 @@ } /* + * Show or change the timestamp configuration for a bpf_if. + */ +static int +bpf_tscfg_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + char tstype_name[16]; + struct bpf_if *bp; + int error, tstype; + + bp = (struct bpf_if *)arg1; + + if (req->newptr == NULL) { + /* Return the name of the BPF interface's timestamp setting. */ + strlcpy(tstype_name, bpftstypes[bp->tstype], + sizeof(tstype_name)); + error = sysctl_handle_string(oidp, tstype_name, + sizeof(tstype_name), req); + } else { + /* Change the timestamp configuration for this BPF interface. */ + error = EINVAL; + for (tstype = 0; tstype < NUM_BPFTSTYPES; tstype++) { + if (strncmp((char *)req->newptr, bpftstypes[tstype], + strlen(bpftstypes[tstype])) == 0) { + bp->tstype = tstype; + error = 0; + break; + } + } + } + + return (error); +} + +/* * Attach an interface to bpf. dlt is the link layer type; hdrlen is the * fixed size of the link header (variable length headers not yet supported). */ @@ -2225,6 +2314,17 @@ if (bp == NULL) panic("bpfattach"); + bp->tscfgoid = SYSCTL_ADD_PROC(NULL, + SYSCTL_STATIC_CHILDREN(_net_bpf_tscfg), OID_AUTO, ifp->if_xname, + CTLTYPE_STRING | CTLFLAG_RW, bp, sizeof(bp), + bpf_tscfg_sysctl_handler, "A", + "Interface BPF timestamp configuration"); + if (bp->tscfgoid == NULL) { + free(bp, M_BPF); + panic("bpfattach tscfgoid"); + } + + bp->tstype = BPF_TSTAMP_NORMAL; LIST_INIT(&bp->bif_dlist); bp->bif_ifp = ifp; bp->bif_dlt = dlt; @@ -2278,6 +2378,7 @@ BPFD_UNLOCK(d); } + sysctl_remove_oid(bp->tscfgoid, 1, 0); mtx_destroy(&bp->bif_mtx); free(bp, M_BPF); } Index: sys/net/bpf.h =================================================================== --- sys/net/bpf.h (revision 228435) +++ sys/net/bpf.h (working copy) @@ -1,12 +1,17 @@ /*- * Copyright (c) 1990, 1991, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. + * Copyright (c) 2011 The University of Melbourne. + * All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * + * Portions of this software were developed by Julien Ridoux at the University + * of Melbourne under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -164,28 +169,43 @@ #define BPF_T_NANOTIME 0x0001 #define BPF_T_BINTIME 0x0002 #define BPF_T_NONE 0x0003 -#define BPF_T_FORMAT_MASK 0x0003 +#define BPF_T_FFCOUNTER 0x0004 +#define BPF_T_FORMAT_MAX 0x0004 +#define BPF_T_FORMAT_MASK 0x0007 #define BPF_T_NORMAL 0x0000 -#define BPF_T_FAST 0x0100 -#define BPF_T_MONOTONIC 0x0200 -#define BPF_T_MONOTONIC_FAST (BPF_T_FAST | BPF_T_MONOTONIC) -#define BPF_T_FLAG_MASK 0x0300 +#define BPF_T_MONOTONIC 0x0100 +#define BPF_T_FLAG_MASK 0x0100 +#define BPF_T_SYSCLOCK 0x0000 +#define BPF_T_FBCLOCK 0x1000 +#define BPF_T_FFCLOCK 0x2000 +#define BPF_T_CLOCK_MAX 0x2000 +#define BPF_T_CLOCK_MASK 0x3000 #define BPF_T_FORMAT(t) ((t) & BPF_T_FORMAT_MASK) #define BPF_T_FLAG(t) ((t) & BPF_T_FLAG_MASK) -#define BPF_T_VALID(t) \ - ((t) == BPF_T_NONE || (BPF_T_FORMAT(t) != BPF_T_NONE && \ - ((t) & ~(BPF_T_FORMAT_MASK | BPF_T_FLAG_MASK)) == 0)) +#define BPF_T_CLOCK(t) ((t) & BPF_T_CLOCK_MASK) +#define BPF_T_VALID(t) \ + ((t) == BPF_T_NONE || (t) == BPF_T_FFCOUNTER || \ + (BPF_T_FORMAT(t) <= BPF_T_BINTIME && BPF_T_CLOCK(t) <= BPF_T_CLOCK_MAX && \ + ((t) & ~(BPF_T_FORMAT_MASK | BPF_T_FLAG_MASK | BPF_T_CLOCK_MASK)) == 0)) -#define BPF_T_MICROTIME_FAST (BPF_T_MICROTIME | BPF_T_FAST) -#define BPF_T_NANOTIME_FAST (BPF_T_NANOTIME | BPF_T_FAST) -#define BPF_T_BINTIME_FAST (BPF_T_BINTIME | BPF_T_FAST) #define BPF_T_MICROTIME_MONOTONIC (BPF_T_MICROTIME | BPF_T_MONOTONIC) #define BPF_T_NANOTIME_MONOTONIC (BPF_T_NANOTIME | BPF_T_MONOTONIC) #define BPF_T_BINTIME_MONOTONIC (BPF_T_BINTIME | BPF_T_MONOTONIC) -#define BPF_T_MICROTIME_MONOTONIC_FAST (BPF_T_MICROTIME | BPF_T_MONOTONIC_FAST) -#define BPF_T_NANOTIME_MONOTONIC_FAST (BPF_T_NANOTIME | BPF_T_MONOTONIC_FAST) -#define BPF_T_BINTIME_MONOTONIC_FAST (BPF_T_BINTIME | BPF_T_MONOTONIC_FAST) +#define BPF_T_FBCLOCK_MICROTIME_MONOTONIC \ + (BPF_T_MICROTIME_MONOTONIC | BPF_T_FBCLOCK) +#define BPF_T_FBCLOCK_NANOTIME_MONOTONIC \ + (BPF_T_NANOTIME_MONOTONIC | BPF_T_FBCLOCK) +#define BPF_T_FBCLOCK_BINTIME_MONOTONIC \ + (BPF_T_BINTIME_MONOTONIC | BPF_T_FBCLOCK) + +#define BPF_T_FFCLOCK_MICROTIME_MONOTONIC \ + (BPF_T_MICROTIME_MONOTONIC | BPF_T_FFCLOCK) +#define BPF_T_FFCLOCK_NANOTIME_MONOTONIC \ + (BPF_T_NANOTIME_MONOTONIC | BPF_T_FFCLOCK) +#define BPF_T_FFCLOCK_BINTIME_MONOTONIC \ + (BPF_T_BINTIME_MONOTONIC | BPF_T_FFCLOCK) + /* * Structure prepended to each packet. */ @@ -193,8 +213,20 @@ bpf_int64 bt_sec; /* seconds */ bpf_u_int64 bt_frac; /* fraction */ }; + +#ifdef FFCLOCK +#define bh_tstamp bh_stamp.time_stamp +#endif + struct bpf_xhdr { +#ifdef FFCLOCK + union { + struct bpf_ts time_stamp; /* time stamp */ + ffcounter ffcount_stamp; /* feed-forward counter */ + } bh_stamp; +#else struct bpf_ts bh_tstamp; /* time stamp */ +#endif bpf_u_int32 bh_caplen; /* length of captured portion */ bpf_u_int32 bh_datalen; /* original length of packet */ u_short bh_hdrlen; /* length of bpf header (this struct @@ -1100,6 +1132,8 @@ u_int bif_hdrlen; /* length of link header */ struct ifnet *bif_ifp; /* corresponding interface */ struct mtx bif_mtx; /* mutex for interface */ + struct sysctl_oid *tscfgoid; /* timestamp sysctl oid for interface */ + int tstype; /* timestamp setting for interface */ }; void bpf_bufheld(struct bpf_d *d);