--- Extend BPF timestamping capabilities when feed-forward clock support is --- enabled: --- --- - Change the various BPF header structs in an ABI preserving way to support --- storing either a regular timestamp or feed-forward counter stamp. --- --- - Add BPF_T_FBCLOCK and BPF_T_FFCLOCK to specify which system clock --- timestamps should be read from. Leaving both of these options unset --- (the default) means the system's current default clock will be used to --- generate timestamps. In contrast, setting one of these options bypasses --- the default clock setting, and will cause the specified system clock to be --- directly queried instead. --- --- - Add BPF_T_FFCOUNTER to specify that the BPF header's bh_stamp union should --- be used to store a feed-forward counter stamp instead of a regular --- timestamp. --- --- BPF consumers can use ioctl() to select the new timestamping options/formats --- per BPF device as required. If feed-forward clock support is not compiled --- into the kernel, attempting to set any of the new flags will have no effect. --- --- Document the changes in the bpf.4 man page. --- --- Committed on behalf of Julien Ridoux and Darryl Veitch from the University of --- Melbourne, Australia, as part of the FreeBSD Foundation funded "Feed-Forward --- Clock Synchronization Algorithms" project. --- --- For more information, see http://www.synclab.org/radclock/ --- --- Discussed with: Julien Ridoux (jridoux at unimelb edu au) --- Submitted by: Julien Ridoux (jridoux at unimelb edu au) --- Index: share/man/man4/bpf.4 =================================================================== --- share/man/man4/bpf.4 (revision 228130) +++ share/man/man4/bpf.4 (working copy) @@ -49,7 +49,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 15, 2010 +.Dd November 30, 2011 .Dt BPF 4 .Os .Sh NAME @@ -516,7 +516,28 @@ .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. +By default, time stamps are derived from the active system clock (feedback or +feed-forward). +Note that the +.Dv BPF_T_FBCLOCK , +.Dv BPF_T_FFCLOCK +and +.Dv BPF_T_FFCOUNTER +options described below are ignored unless the kernel has been compiled with +feed-forward clock support (see +.Xr ffclock 4 +for more details). +.Pp +Individual BPF devices can be independently configured to use the feedback or +feed-forward clock if required. +Any time stamp format and resolution described below can be OR'ed with either +.Dv BPF_T_FBCLOCK +or +.Dv BPF_T_FFCLOCK +to specify that the BPF device should explicitly use the feedback or +feed-forward clock respectively for time stamp generation. +.Pp Set to .Dv BPF_T_MICROTIME , .Dv BPF_T_MICROTIME_FAST , @@ -545,8 +566,16 @@ .Vt struct bintime format. Set to +.Dv BPF_T_FFCOUNTER +to get a 64-bit feed-forward counter value. +A valid feed-forward counter value will only be returned if +.Dv BPF_T_FFCLOCK +is set or the active system clock is the feed-forward clock, otherwise a value +of 0 will be returned. +Set to .Dv BPF_T_NONE to ignore time stamp. +.Pp All 64-bit time stamp formats are wrapped in .Vt struct bpf_ts . The @@ -1021,6 +1050,7 @@ .Xr poll 2 , .Xr select 2 , .Xr byteorder 3 , +.Xr ffclock 4 , .Xr ng_bpf 4 , .Xr bpf 9 .Rs Index: sys/net/bpf.c =================================================================== --- sys/net/bpf.c (revision 228132) +++ 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 FreeBSD Foundation. + * 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,9 @@ #include #include #include +#ifdef FFCLOCK +#include +#endif #include #include @@ -106,7 +115,14 @@ * 32-bit the first time we see a 32-bit compat ioctl request. */ struct bpf_hdr32 { +#ifdef FFCLOCK + union { + struct timeval32 time_stamp; /* time stamp */ + ffcounter ffcount_stamp; /* f-forward counter */ + } bh_stamp; +#else struct timeval32 bh_tstamp; /* time stamp */ +#endif uint32_t bh_caplen; /* length of captured portion */ uint32_t bh_datalen; /* original length of packet */ uint16_t bh_hdrlen; /* length of bpf header (this struct @@ -132,7 +148,18 @@ #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) #endif +#ifdef FFCLOCK /* + * Safety belt to ensure ABI of structs bpf_hdr32, bpf_hdr and bpf_xhdr are + * preserved when FFCLOCK is enabled, which changes the stamp field in the + * structs to allow storing a regular time stamp or ffcounter stamp. + */ +CTASSERT(sizeof(struct timeval32) >= sizeof(ffcounter) && + sizeof(struct timeval) >= sizeof(ffcounter) && + sizeof(struct bpf_ts) >= sizeof(ffcounter)); +#endif + +/* * 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 @@ -153,7 +180,11 @@ bpf_wakeup(struct bpf_d *); static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), +#ifdef FFCLOCK + struct bintime *, ffcounter *); +#else struct bintime *); +#endif static void reset_d(struct bpf_d *); static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); @@ -1777,10 +1808,17 @@ } static int +#ifdef FFCLOCK +bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m, ffcounter *ffcount) +#else bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) +#endif { struct m_tag *tag; int quality; +#ifdef FFCLOCK + int ff_flags; +#endif quality = bpf_ts_quality(tstype); if (quality == BPF_TSTAMP_NONE) @@ -1793,11 +1831,66 @@ return (BPF_TSTAMP_EXTERN); } } - if (quality == BPF_TSTAMP_NORMAL) - binuptime(bt); - else - getbinuptime(bt); +#ifdef FFCLOCK + switch(BPF_T_CLOCK(tstype)) { + case BPF_T_FFCLOCK: + if (tstype & BPF_T_FFCOUNTER) { + ffclock_read_counter(ffcount); + } else { + ff_flags = FFCLOCK_LERP; + if (tstype & BPF_T_MONOTONIC) + ff_flags |= FFCLOCK_UPTIME; + else + ff_flags |= FFCLOCK_LEAPSEC; + if (quality == BPF_TSTAMP_FAST) + ff_flags |= FFCLOCK_FAST; + ffclock_abstime(ffcount, bt, NULL, ff_flags); + } + break; + case BPF_T_FBCLOCK: + if (tstype & BPF_T_FFCOUNTER) { + *ffcount = 0; + } else { + if (quality == BPF_TSTAMP_NORMAL) { + if (tstype & BPF_T_MONOTONIC) + binuptime_fromclock(bt, SYSCLOCK_FBCK); + else + bintime_fromclock(bt, SYSCLOCK_FBCK); + } else { + if (tstype & BPF_T_MONOTONIC) + getbinuptime_fromclock(bt, + SYSCLOCK_FBCK); + else + getbintime_fromclock(bt, SYSCLOCK_FBCK); + } + } + break; + default: + if (tstype & BPF_T_FFCOUNTER) { + if (sysclock_active == SYSCLOCK_FFWD) + ffclock_read_counter(ffcount); + else + *ffcount = 0; + } else { +#endif + if (quality == BPF_TSTAMP_NORMAL) { + if (tstype & BPF_T_MONOTONIC) + binuptime(bt); + else + bintime(bt); + } else { + if (tstype & BPF_T_MONOTONIC) + getbinuptime(bt); + else + getbintime(bt); + } +#ifdef FFCLOCK + } + break; + } +#endif + return (quality); } @@ -1817,6 +1910,9 @@ #endif u_int slen; int gottime; +#ifdef FFCLOCK + ffcounter ffcount; +#endif gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); @@ -1838,13 +1934,23 @@ slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) { d->bd_fcount++; - if (gottime < bpf_ts_quality(d->bd_tstamp)) + if (gottime < bpf_ts_quality(d->bd_tstamp)) { +#ifdef FFCLOCK + gottime = bpf_gettime(&bt, d->bd_tstamp, NULL, + &ffcount); +#else gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); +#endif + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, pkt, pktlen, slen, +#ifdef FFCLOCK + bpf_append_bytes, &bt, &ffcount); +#else bpf_append_bytes, &bt); +#endif } BPFD_UNLOCK(d); } @@ -1868,6 +1974,9 @@ #endif u_int pktlen, slen; int gottime; +#ifdef FFCLOCK + ffcounter ffcount; +#endif /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1895,12 +2004,23 @@ if (slen != 0) { d->bd_fcount++; if (gottime < bpf_ts_quality(d->bd_tstamp)) + { +#ifdef FFCLOCK + gottime = bpf_gettime(&bt, d->bd_tstamp, m, + &ffcount); +#else gottime = bpf_gettime(&bt, d->bd_tstamp, m); +#endif + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)m, pktlen, slen, +#ifdef FFCLOCK + bpf_append_mbuf, &bt, &ffcount); +#else bpf_append_mbuf, &bt); +#endif } BPFD_UNLOCK(d); } @@ -1919,6 +2039,9 @@ struct bpf_d *d; u_int pktlen, slen; int gottime; +#ifdef FFCLOCK + ffcounter ffcount; +#endif /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1948,12 +2071,23 @@ if (slen != 0) { d->bd_fcount++; if (gottime < bpf_ts_quality(d->bd_tstamp)) + { +#ifdef FFCLOCK + gottime = bpf_gettime(&bt, d->bd_tstamp, m, + &ffcount); +#else gottime = bpf_gettime(&bt, d->bd_tstamp, m); +#endif + } #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)&mb, pktlen, slen, +#ifdef FFCLOCK + bpf_append_mbuf, &bt, &ffcount); +#else bpf_append_mbuf, &bt); +#endif } BPFD_UNLOCK(d); } @@ -1998,15 +2132,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); @@ -2035,7 +2163,11 @@ static void catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), +#ifdef FFCLOCK + struct bintime *bt, ffcounter *ffcount) +#else struct bintime *bt) +#endif { struct bpf_xhdr hdr; #ifndef BURN_BRIDGES @@ -2153,8 +2285,14 @@ * 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) + hdr.bh_stamp.ffcount_stamp = *ffcount; + else +#endif + bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); + } hdr.bh_datalen = pktlen; hdr.bh_hdrlen = hdrlen; hdr.bh_caplen = caplen; Index: sys/net/bpf.h =================================================================== --- sys/net/bpf.h (revision 228132) +++ 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 FreeBSD Foundation + * 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,17 +169,22 @@ #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_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_FBCLOCK 0x1000 +#define BPF_T_FFCLOCK 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_CLOCK(t) ((t) & BPF_T_CLOCK_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)) + ((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) @@ -193,8 +203,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 @@ -202,7 +224,14 @@ }; /* Obsolete */ struct bpf_hdr { +#ifdef FFCLOCK + union { + struct timeval time_stamp; /* time stamp */ + ffcounter ffcount_stamp; /* feed-forward counter */ + } bh_stamp; +#else struct timeval 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