Implement flexible BPF timestamping framework.
- Allow setting format, resolution and accuracy of BPF time stamps per listener. Previously, we were only able to use microtime(9). Now we can set various resolutions and accuracies with ioctl(2) BIOCSTSTAMP command. Similarly, we can get the current resolution and accuracy with BIOCGTSTAMP command. Document all supported options in bpf(4) and their uses. - Introduce new time stamp 'struct bpf_ts' and header 'struct bpf_xhdr'. The new time stamp has both 64-bit second and fractional parts. bpf_xhdr has this time stamp instead of 'struct timeval' for bh_tstamp. The new structures let us use bh_tstamp of same size on both 32-bit and 64-bit platforms without adding additional shims for 32-bit binaries. On 64-bit platforms, size of BPF header does not change compared to bpf_hdr as its members are already all 64-bit long. On 32-bit platforms, the size may increase by 8 bytes. For backward compatibility, struct bpf_hdr with struct timeval is still the default header unless new time stamp format is explicitly requested. However, the behaviour may change in the future and all relevant code is wrapped around "#ifdef BURN_BRIDGES" for now. - Add experimental support for tagging mbufs with time stamps from a lower layer, e.g., device driver. Currently, mbuf_tags(9) is used to tag mbufs. The time stamps must be uptime in 'struct bintime' format as binuptime(9) and getbinuptime(9) do. Reviewed by: net@
This commit is contained in:
parent
bf96595915
commit
547d94bde3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=209216
@ -49,7 +49,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 26, 2007
|
||||
.Dd June 15, 2010
|
||||
.Dt BPF 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -513,6 +513,64 @@ to see only outgoing packets on the interface.
|
||||
This setting is initialized to
|
||||
.Dv BPF_D_INOUT
|
||||
by default.
|
||||
.It Dv BIOCSTSTAMP
|
||||
.It Dv BIOCGTSTAMP
|
||||
.Pq Li u_int
|
||||
Set or get format and resolution of the time stamps returned by BPF.
|
||||
Set to
|
||||
.Dv BPF_T_MICROTIME ,
|
||||
.Dv BPF_T_MICROTIME_FAST ,
|
||||
.Dv BPF_T_MICROTIME_MONOTONIC ,
|
||||
or
|
||||
.Dv BPF_T_MICROTIME_MONOTONIC_FAST
|
||||
to get time stamps in 64-bit
|
||||
.Vt struct timeval
|
||||
format.
|
||||
Set to
|
||||
.Dv BPF_T_NANOTIME ,
|
||||
.Dv BPF_T_NANOTIME_FAST ,
|
||||
.Dv BPF_T_NANOTIME_MONOTONIC ,
|
||||
or
|
||||
.Dv BPF_T_NANOTIME_MONOTONIC_FAST
|
||||
to get time stamps in 64-bit
|
||||
.Vt struct timespec
|
||||
format.
|
||||
Set to
|
||||
.Dv BPF_T_BINTIME ,
|
||||
.Dv BPF_T_BINTIME_FAST ,
|
||||
.Dv BPF_T_NANOTIME_MONOTONIC ,
|
||||
or
|
||||
.Dv BPF_T_BINTIME_MONOTONIC_FAST
|
||||
to get time stamps in 64-bit
|
||||
.Vt struct bintime
|
||||
format.
|
||||
Set to
|
||||
.Dv BPF_T_NONE
|
||||
to ignore time stamp.
|
||||
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_MICROTIME_MONOTONIC_FAST ,
|
||||
.Dv BPF_T_NANOTIME_MONOTONIC_FAST ,
|
||||
and
|
||||
.Dv BPF_T_BINTIME_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_MICROTIME_MONOTONIC_FAST ,
|
||||
.Dv BPF_T_NANOTIME_MONOTONIC_FAST ,
|
||||
and
|
||||
.Dv BPF_T_BINTIME_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.
|
||||
@ -575,16 +633,24 @@ against
|
||||
.Vt bzh_user_gen .
|
||||
.El
|
||||
.Sh BPF HEADER
|
||||
The following structure is prepended to each packet returned by
|
||||
One of the following structures is prepended to each packet returned by
|
||||
.Xr read 2
|
||||
or via a zero-copy buffer:
|
||||
.Bd -literal
|
||||
struct bpf_xhdr {
|
||||
struct bpf_ts bh_tstamp; /* time stamp */
|
||||
uint32_t bh_caplen; /* length of captured portion */
|
||||
uint32_t bh_datalen; /* original length of packet */
|
||||
u_short bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding */
|
||||
};
|
||||
|
||||
struct bpf_hdr {
|
||||
struct timeval bh_tstamp; /* time stamp */
|
||||
u_long bh_caplen; /* length of captured portion */
|
||||
u_long bh_datalen; /* original length of packet */
|
||||
u_short bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding */
|
||||
struct timeval bh_tstamp; /* time stamp */
|
||||
uint32_t bh_caplen; /* length of captured portion */
|
||||
uint32_t bh_datalen; /* original length of packet */
|
||||
u_short bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
@ -605,6 +671,8 @@ The length of the
|
||||
.Nm
|
||||
header, which may not be equal to
|
||||
.\" XXX - not really a function call
|
||||
.Fn sizeof "struct bpf_xhdr"
|
||||
or
|
||||
.Fn sizeof "struct bpf_hdr" .
|
||||
.El
|
||||
.Pp
|
||||
@ -616,9 +684,24 @@ The purpose here is to guarantee proper alignment of the packet
|
||||
data structures, which is required on alignment sensitive
|
||||
architectures and improves performance on many other architectures.
|
||||
The packet filter insures that the
|
||||
.Li bpf_hdr
|
||||
.Vt bpf_xhdr ,
|
||||
.Vt bpf_hdr
|
||||
and the network layer
|
||||
header will be word aligned.
|
||||
Currently,
|
||||
.Vt bpf_hdr
|
||||
is used when the time stamp is set to
|
||||
.Dv BPF_T_MICROTIME ,
|
||||
.Dv BPF_T_MICROTIME_FAST ,
|
||||
.Dv BPF_T_MICROTIME_MONOTONIC ,
|
||||
.Dv BPF_T_MICROTIME_MONOTONIC_FAST ,
|
||||
or
|
||||
.Dv BPF_T_NONE
|
||||
for backward compatibility reasons. Otherwise,
|
||||
.Vt bpf_xhdr
|
||||
is used. However,
|
||||
.Vt bpf_hdr
|
||||
may be deprecated in the near future.
|
||||
Suitable precautions
|
||||
must be taken when accessing the link layer protocol fields on alignment
|
||||
restricted machines.
|
||||
|
@ -90,7 +90,7 @@ static struct timecounter *timecounters = &dummy_timecounter;
|
||||
time_t time_second = 1;
|
||||
time_t time_uptime = 1;
|
||||
|
||||
static struct bintime boottimebin;
|
||||
struct bintime boottimebin;
|
||||
struct timeval boottime;
|
||||
static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
|
||||
SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
|
||||
|
263
sys/net/bpf.c
263
sys/net/bpf.c
@ -90,12 +90,16 @@ MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
|
||||
|
||||
#define PRINET 26 /* interruptible */
|
||||
|
||||
#define SIZEOF_BPF_HDR(type) \
|
||||
(offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen))
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
#include <sys/mount.h>
|
||||
#include <compat/freebsd32/freebsd32.h>
|
||||
#define BPF_ALIGNMENT32 sizeof(int32_t)
|
||||
#define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1))
|
||||
|
||||
#ifndef BURN_BRIDGES
|
||||
/*
|
||||
* 32-bit version of structure prepended to each packet. We use this header
|
||||
* instead of the standard one for 32-bit streams. We mark the a stream as
|
||||
@ -108,6 +112,7 @@ struct bpf_hdr32 {
|
||||
uint16_t bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding) */
|
||||
};
|
||||
#endif
|
||||
|
||||
struct bpf_program32 {
|
||||
u_int bf_len;
|
||||
@ -120,11 +125,11 @@ struct bpf_dltlist32 {
|
||||
};
|
||||
|
||||
#define BIOCSETF32 _IOW('B', 103, struct bpf_program32)
|
||||
#define BIOCSRTIMEOUT32 _IOW('B',109, struct timeval32)
|
||||
#define BIOCGRTIMEOUT32 _IOR('B',110, struct timeval32)
|
||||
#define BIOCGDLTLIST32 _IOWR('B',121, struct bpf_dltlist32)
|
||||
#define BIOCSETWF32 _IOW('B',123, struct bpf_program32)
|
||||
#define BIOCSETFNR32 _IOW('B',130, struct bpf_program32)
|
||||
#define BIOCSRTIMEOUT32 _IOW('B', 109, struct timeval32)
|
||||
#define BIOCGRTIMEOUT32 _IOR('B', 110, struct timeval32)
|
||||
#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
|
||||
|
||||
/*
|
||||
@ -148,7 +153,7 @@ static __inline void
|
||||
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),
|
||||
struct timeval *);
|
||||
struct bintime *);
|
||||
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 *);
|
||||
@ -1007,6 +1012,8 @@ reset_d(struct bpf_d *d)
|
||||
* BIOCSHDRCMPLT Set "header already complete" flag
|
||||
* BIOCGDIRECTION Get packet direction flag
|
||||
* BIOCSDIRECTION Set packet direction flag
|
||||
* BIOCGTSTAMP Get time stamp format and resolution.
|
||||
* BIOCSTSTAMP Set time stamp format and resolution.
|
||||
* BIOCLOCK Set "locked" flag
|
||||
* BIOCFEEDBACK Set packet feedback mode.
|
||||
* BIOCSETZBUF Set current zero-copy buffer locations.
|
||||
@ -1055,6 +1062,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
||||
case BIOCVERSION:
|
||||
case BIOCGRSIG:
|
||||
case BIOCGHDRCMPLT:
|
||||
case BIOCSTSTAMP:
|
||||
case BIOCFEEDBACK:
|
||||
case FIONREAD:
|
||||
case BIOCLOCK:
|
||||
@ -1383,6 +1391,28 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Set packet timestamp format and resolution.
|
||||
*/
|
||||
case BIOCGTSTAMP:
|
||||
*(u_int *)addr = d->bd_tstamp;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Set packet timestamp format and resolution.
|
||||
*/
|
||||
case BIOCSTSTAMP:
|
||||
{
|
||||
u_int func;
|
||||
|
||||
func = *(u_int *)addr;
|
||||
if (BPF_T_VALID(func))
|
||||
d->bd_tstamp = func;
|
||||
else
|
||||
error = EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIOCFEEDBACK:
|
||||
d->bd_feedback = *(u_int *)addr;
|
||||
break;
|
||||
@ -1729,6 +1759,48 @@ filt_bpfread(struct knote *kn, long hint)
|
||||
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
|
||||
@ -1738,15 +1810,15 @@ filt_bpfread(struct knote *kn, long hint)
|
||||
void
|
||||
bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen)
|
||||
{
|
||||
struct bintime bt;
|
||||
struct bpf_d *d;
|
||||
#ifdef BPF_JITTER
|
||||
bpf_jit_filter *bf;
|
||||
#endif
|
||||
u_int slen;
|
||||
int gottime;
|
||||
struct timeval tv;
|
||||
|
||||
gottime = 0;
|
||||
gottime = BPF_TSTAMP_NONE;
|
||||
BPFIF_LOCK(bp);
|
||||
LIST_FOREACH(d, &bp->bif_dlist, bd_next) {
|
||||
BPFD_LOCK(d);
|
||||
@ -1766,15 +1838,13 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen)
|
||||
slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen);
|
||||
if (slen != 0) {
|
||||
d->bd_fcount++;
|
||||
if (!gottime) {
|
||||
microtime(&tv);
|
||||
gottime = 1;
|
||||
}
|
||||
if (gottime < bpf_ts_quality(d->bd_tstamp))
|
||||
gottime = bpf_gettime(&bt, d->bd_tstamp, NULL);
|
||||
#ifdef MAC
|
||||
if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
catchpacket(d, pkt, pktlen, slen,
|
||||
bpf_append_bytes, &tv);
|
||||
bpf_append_bytes, &bt);
|
||||
}
|
||||
BPFD_UNLOCK(d);
|
||||
}
|
||||
@ -1791,13 +1861,13 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen)
|
||||
void
|
||||
bpf_mtap(struct bpf_if *bp, struct mbuf *m)
|
||||
{
|
||||
struct bintime bt;
|
||||
struct bpf_d *d;
|
||||
#ifdef BPF_JITTER
|
||||
bpf_jit_filter *bf;
|
||||
#endif
|
||||
u_int pktlen, slen;
|
||||
int gottime;
|
||||
struct timeval tv;
|
||||
|
||||
/* Skip outgoing duplicate packets. */
|
||||
if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) {
|
||||
@ -1805,10 +1875,9 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m)
|
||||
return;
|
||||
}
|
||||
|
||||
gottime = 0;
|
||||
|
||||
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))
|
||||
@ -1825,15 +1894,13 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m)
|
||||
slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0);
|
||||
if (slen != 0) {
|
||||
d->bd_fcount++;
|
||||
if (!gottime) {
|
||||
microtime(&tv);
|
||||
gottime = 1;
|
||||
}
|
||||
if (gottime < bpf_ts_quality(d->bd_tstamp))
|
||||
gottime = bpf_gettime(&bt, d->bd_tstamp, m);
|
||||
#ifdef MAC
|
||||
if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
catchpacket(d, (u_char *)m, pktlen, slen,
|
||||
bpf_append_mbuf, &tv);
|
||||
bpf_append_mbuf, &bt);
|
||||
}
|
||||
BPFD_UNLOCK(d);
|
||||
}
|
||||
@ -1847,11 +1914,11 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m)
|
||||
void
|
||||
bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
{
|
||||
struct bintime bt;
|
||||
struct mbuf mb;
|
||||
struct bpf_d *d;
|
||||
u_int pktlen, slen;
|
||||
int gottime;
|
||||
struct timeval tv;
|
||||
|
||||
/* Skip outgoing duplicate packets. */
|
||||
if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) {
|
||||
@ -1859,8 +1926,6 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
return;
|
||||
}
|
||||
|
||||
gottime = 0;
|
||||
|
||||
pktlen = m_length(m, NULL);
|
||||
/*
|
||||
* Craft on-stack mbuf suitable for passing to bpf_filter.
|
||||
@ -1872,6 +1937,7 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
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))
|
||||
@ -1881,15 +1947,13 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0);
|
||||
if (slen != 0) {
|
||||
d->bd_fcount++;
|
||||
if (!gottime) {
|
||||
microtime(&tv);
|
||||
gottime = 1;
|
||||
}
|
||||
if (gottime < bpf_ts_quality(d->bd_tstamp))
|
||||
gottime = bpf_gettime(&bt, d->bd_tstamp, m);
|
||||
#ifdef MAC
|
||||
if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
catchpacket(d, (u_char *)&mb, pktlen, slen,
|
||||
bpf_append_mbuf, &tv);
|
||||
bpf_append_mbuf, &bt);
|
||||
}
|
||||
BPFD_UNLOCK(d);
|
||||
}
|
||||
@ -1898,6 +1962,69 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
|
||||
#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)
|
||||
{
|
||||
int hdrlen;
|
||||
|
||||
hdrlen = d->bd_bif->bif_hdrlen;
|
||||
#ifndef BURN_BRIDGES
|
||||
if (d->bd_tstamp == BPF_T_NONE ||
|
||||
BPF_T_FORMAT(d->bd_tstamp) == BPF_T_MICROTIME)
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
if (d->bd_compat32)
|
||||
hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr32);
|
||||
else
|
||||
#endif
|
||||
hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr);
|
||||
else
|
||||
#endif
|
||||
hdrlen += SIZEOF_BPF_HDR(struct bpf_xhdr);
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
if (d->bd_compat32)
|
||||
hdrlen = BPF_WORDALIGN32(hdrlen);
|
||||
else
|
||||
#endif
|
||||
hdrlen = BPF_WORDALIGN(hdrlen);
|
||||
|
||||
return (hdrlen - d->bd_bif->bif_hdrlen);
|
||||
}
|
||||
|
||||
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);
|
||||
ts->bt_sec = tsm.tv_sec;
|
||||
ts->bt_frac = tsm.tv_usec;
|
||||
break;
|
||||
case BPF_T_NANOTIME:
|
||||
bintime2timespec(bt, &tsn);
|
||||
ts->bt_sec = tsn.tv_sec;
|
||||
ts->bt_frac = tsn.tv_nsec;
|
||||
break;
|
||||
case BPF_T_BINTIME:
|
||||
ts->bt_sec = bt->sec;
|
||||
ts->bt_frac = bt->frac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the packet data from interface memory (pkt) into the
|
||||
* store buffer. "cpfn" is the routine called to do the actual data
|
||||
@ -1908,15 +2035,19 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
|
||||
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),
|
||||
struct timeval *tv)
|
||||
struct bintime *bt)
|
||||
{
|
||||
struct bpf_hdr hdr;
|
||||
struct bpf_xhdr hdr;
|
||||
#ifndef BURN_BRIDGES
|
||||
struct bpf_hdr hdr_old;
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
struct bpf_hdr32 hdr32;
|
||||
struct bpf_hdr32 hdr32_old;
|
||||
#endif
|
||||
int totlen, curlen;
|
||||
int hdrlen = d->bd_bif->bif_hdrlen;
|
||||
#endif
|
||||
int caplen, curlen, hdrlen, totlen;
|
||||
int do_wakeup = 0;
|
||||
int do_timestamp;
|
||||
int tstype;
|
||||
|
||||
BPFD_LOCK_ASSERT(d);
|
||||
|
||||
@ -1940,6 +2071,7 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
|
||||
* much. Otherwise, transfer the whole packet (unless
|
||||
* we hit the buffer size limit).
|
||||
*/
|
||||
hdrlen = bpf_hdrlen(d);
|
||||
totlen = hdrlen + min(snaplen, pktlen);
|
||||
if (totlen > d->bd_bufsize)
|
||||
totlen = d->bd_bufsize;
|
||||
@ -1979,19 +2111,39 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
|
||||
* reader should be woken up.
|
||||
*/
|
||||
do_wakeup = 1;
|
||||
caplen = totlen - hdrlen;
|
||||
tstype = d->bd_tstamp;
|
||||
do_timestamp = tstype != BPF_T_NONE;
|
||||
#ifndef BURN_BRIDGES
|
||||
if (tstype == BPF_T_NONE || BPF_T_FORMAT(tstype) == BPF_T_MICROTIME) {
|
||||
struct bpf_ts ts;
|
||||
if (do_timestamp)
|
||||
bpf_bintime2ts(bt, &ts, tstype);
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
/*
|
||||
* If this is a 32-bit stream, then stick a 32-bit header at the
|
||||
* front and copy the data into the buffer.
|
||||
*/
|
||||
if (d->bd_compat32) {
|
||||
bzero(&hdr32, sizeof(hdr32));
|
||||
hdr32.bh_tstamp.tv_sec = tv->tv_sec;
|
||||
hdr32.bh_tstamp.tv_usec = tv->tv_usec;
|
||||
hdr32.bh_datalen = pktlen;
|
||||
hdr32.bh_hdrlen = hdrlen;
|
||||
hdr.bh_caplen = hdr32.bh_caplen = totlen - hdrlen;
|
||||
bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32, sizeof(hdr32));
|
||||
if (d->bd_compat32) {
|
||||
bzero(&hdr32_old, sizeof(hdr32_old));
|
||||
if (do_timestamp) {
|
||||
hdr32_old.bh_tstamp.tv_sec = ts.bt_sec;
|
||||
hdr32_old.bh_tstamp.tv_usec = ts.bt_frac;
|
||||
}
|
||||
hdr32_old.bh_datalen = pktlen;
|
||||
hdr32_old.bh_hdrlen = hdrlen;
|
||||
hdr32_old.bh_caplen = caplen;
|
||||
bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32_old,
|
||||
sizeof(hdr32_old));
|
||||
goto copy;
|
||||
}
|
||||
#endif
|
||||
bzero(&hdr_old, sizeof(hdr_old));
|
||||
if (do_timestamp) {
|
||||
hdr_old.bh_tstamp.tv_sec = ts.bt_sec;
|
||||
hdr_old.bh_tstamp.tv_usec = ts.bt_frac;
|
||||
}
|
||||
hdr_old.bh_datalen = pktlen;
|
||||
hdr_old.bh_hdrlen = hdrlen;
|
||||
hdr_old.bh_caplen = caplen;
|
||||
bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr_old,
|
||||
sizeof(hdr_old));
|
||||
goto copy;
|
||||
}
|
||||
#endif
|
||||
@ -2001,19 +2153,20 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
|
||||
* move forward the length of the header plus padding.
|
||||
*/
|
||||
bzero(&hdr, sizeof(hdr));
|
||||
hdr.bh_tstamp = *tv;
|
||||
if (do_timestamp)
|
||||
bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype);
|
||||
hdr.bh_datalen = pktlen;
|
||||
hdr.bh_hdrlen = hdrlen;
|
||||
hdr.bh_caplen = totlen - hdrlen;
|
||||
hdr.bh_caplen = caplen;
|
||||
bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr));
|
||||
|
||||
/*
|
||||
* Copy the packet data into the store buffer and update its length.
|
||||
*/
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
copy:
|
||||
#ifndef BURN_BRIDGES
|
||||
copy:
|
||||
#endif
|
||||
(*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, hdr.bh_caplen);
|
||||
(*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, caplen);
|
||||
d->bd_slen = curlen + totlen;
|
||||
|
||||
if (do_wakeup)
|
||||
@ -2083,13 +2236,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp)
|
||||
LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next);
|
||||
mtx_unlock(&bpf_mtx);
|
||||
|
||||
/*
|
||||
* Compute the length of the bpf header. This is not necessarily
|
||||
* equal to SIZEOF_BPF_HDR because we want to insert spacing such
|
||||
* that the network layer header begins on a longword boundary (for
|
||||
* performance reasons and to alleviate alignment restrictions).
|
||||
*/
|
||||
bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
|
||||
bp->bif_hdrlen = hdrlen;
|
||||
|
||||
if (bootverbose)
|
||||
if_printf(ifp, "bpf attached\n");
|
||||
|
112
sys/net/bpf.h
112
sys/net/bpf.h
@ -45,6 +45,8 @@
|
||||
|
||||
typedef int32_t bpf_int32;
|
||||
typedef u_int32_t bpf_u_int32;
|
||||
typedef int64_t bpf_int64;
|
||||
typedef u_int64_t bpf_u_int64;
|
||||
|
||||
/*
|
||||
* Alignment macros. BPF_WORDALIGN rounds up to the next
|
||||
@ -113,36 +115,38 @@ struct bpf_zbuf {
|
||||
size_t bz_buflen; /* Size of zero-copy buffers. */
|
||||
};
|
||||
|
||||
#define BIOCGBLEN _IOR('B',102, u_int)
|
||||
#define BIOCSBLEN _IOWR('B',102, u_int)
|
||||
#define BIOCSETF _IOW('B',103, struct bpf_program)
|
||||
#define BIOCFLUSH _IO('B',104)
|
||||
#define BIOCPROMISC _IO('B',105)
|
||||
#define BIOCGDLT _IOR('B',106, u_int)
|
||||
#define BIOCGETIF _IOR('B',107, struct ifreq)
|
||||
#define BIOCSETIF _IOW('B',108, struct ifreq)
|
||||
#define BIOCSRTIMEOUT _IOW('B',109, struct timeval)
|
||||
#define BIOCGRTIMEOUT _IOR('B',110, struct timeval)
|
||||
#define BIOCGSTATS _IOR('B',111, struct bpf_stat)
|
||||
#define BIOCIMMEDIATE _IOW('B',112, u_int)
|
||||
#define BIOCVERSION _IOR('B',113, struct bpf_version)
|
||||
#define BIOCGRSIG _IOR('B',114, u_int)
|
||||
#define BIOCSRSIG _IOW('B',115, u_int)
|
||||
#define BIOCGHDRCMPLT _IOR('B',116, u_int)
|
||||
#define BIOCSHDRCMPLT _IOW('B',117, u_int)
|
||||
#define BIOCGDIRECTION _IOR('B',118, u_int)
|
||||
#define BIOCSDIRECTION _IOW('B',119, u_int)
|
||||
#define BIOCSDLT _IOW('B',120, u_int)
|
||||
#define BIOCGDLTLIST _IOWR('B',121, struct bpf_dltlist)
|
||||
#define BIOCGBLEN _IOR('B', 102, u_int)
|
||||
#define BIOCSBLEN _IOWR('B', 102, u_int)
|
||||
#define BIOCSETF _IOW('B', 103, struct bpf_program)
|
||||
#define BIOCFLUSH _IO('B', 104)
|
||||
#define BIOCPROMISC _IO('B', 105)
|
||||
#define BIOCGDLT _IOR('B', 106, u_int)
|
||||
#define BIOCGETIF _IOR('B', 107, struct ifreq)
|
||||
#define BIOCSETIF _IOW('B', 108, struct ifreq)
|
||||
#define BIOCSRTIMEOUT _IOW('B', 109, struct timeval)
|
||||
#define BIOCGRTIMEOUT _IOR('B', 110, struct timeval)
|
||||
#define BIOCGSTATS _IOR('B', 111, struct bpf_stat)
|
||||
#define BIOCIMMEDIATE _IOW('B', 112, u_int)
|
||||
#define BIOCVERSION _IOR('B', 113, struct bpf_version)
|
||||
#define BIOCGRSIG _IOR('B', 114, u_int)
|
||||
#define BIOCSRSIG _IOW('B', 115, u_int)
|
||||
#define BIOCGHDRCMPLT _IOR('B', 116, u_int)
|
||||
#define BIOCSHDRCMPLT _IOW('B', 117, u_int)
|
||||
#define BIOCGDIRECTION _IOR('B', 118, u_int)
|
||||
#define BIOCSDIRECTION _IOW('B', 119, u_int)
|
||||
#define BIOCSDLT _IOW('B', 120, u_int)
|
||||
#define BIOCGDLTLIST _IOWR('B', 121, struct bpf_dltlist)
|
||||
#define BIOCLOCK _IO('B', 122)
|
||||
#define BIOCSETWF _IOW('B',123, struct bpf_program)
|
||||
#define BIOCFEEDBACK _IOW('B',124, u_int)
|
||||
#define BIOCGETBUFMODE _IOR('B',125, u_int)
|
||||
#define BIOCSETBUFMODE _IOW('B',126, u_int)
|
||||
#define BIOCGETZMAX _IOR('B',127, size_t)
|
||||
#define BIOCROTZBUF _IOR('B',128, struct bpf_zbuf)
|
||||
#define BIOCSETZBUF _IOW('B',129, struct bpf_zbuf)
|
||||
#define BIOCSETFNR _IOW('B',130, struct bpf_program)
|
||||
#define BIOCSETWF _IOW('B', 123, struct bpf_program)
|
||||
#define BIOCFEEDBACK _IOW('B', 124, u_int)
|
||||
#define BIOCGETBUFMODE _IOR('B', 125, u_int)
|
||||
#define BIOCSETBUFMODE _IOW('B', 126, u_int)
|
||||
#define BIOCGETZMAX _IOR('B', 127, size_t)
|
||||
#define BIOCROTZBUF _IOR('B', 128, struct bpf_zbuf)
|
||||
#define BIOCSETZBUF _IOW('B', 129, struct bpf_zbuf)
|
||||
#define BIOCSETFNR _IOW('B', 130, struct bpf_program)
|
||||
#define BIOCGTSTAMP _IOR('B', 131, u_int)
|
||||
#define BIOCSTSTAMP _IOW('B', 132, u_int)
|
||||
|
||||
/* Obsolete */
|
||||
#define BIOCGSEESENT BIOCGDIRECTION
|
||||
@ -155,9 +159,48 @@ enum bpf_direction {
|
||||
BPF_D_OUT /* See outgoing packets */
|
||||
};
|
||||
|
||||
/* Time stamping functions */
|
||||
#define BPF_T_MICROTIME 0x0000
|
||||
#define BPF_T_NANOTIME 0x0001
|
||||
#define BPF_T_BINTIME 0x0002
|
||||
#define BPF_T_NONE 0x0003
|
||||
#define BPF_T_FORMAT_MASK 0x0003
|
||||
#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_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_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)
|
||||
|
||||
/*
|
||||
* Structure prepended to each packet.
|
||||
*/
|
||||
struct bpf_ts {
|
||||
bpf_int64 bt_sec; /* seconds */
|
||||
bpf_u_int64 bt_frac; /* fraction */
|
||||
};
|
||||
struct bpf_xhdr {
|
||||
struct bpf_ts bh_tstamp; /* time stamp */
|
||||
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
|
||||
plus alignment padding) */
|
||||
};
|
||||
/* Obsolete */
|
||||
struct bpf_hdr {
|
||||
struct timeval bh_tstamp; /* time stamp */
|
||||
bpf_u_int32 bh_caplen; /* length of captured portion */
|
||||
@ -165,14 +208,9 @@ struct bpf_hdr {
|
||||
u_short bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding) */
|
||||
};
|
||||
/*
|
||||
* Because the structure above is not a multiple of 4 bytes, some compilers
|
||||
* will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
|
||||
* Only the kernel needs to know about it; applications use bh_hdrlen.
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
#define SIZEOF_BPF_HDR (sizeof(struct bpf_hdr) <= 20 ? 18 : \
|
||||
sizeof(struct bpf_hdr))
|
||||
#define MTAG_BPF 0x627066
|
||||
#define MTAG_BPF_TIMESTAMP 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -922,7 +960,7 @@ struct bpf_if {
|
||||
LIST_ENTRY(bpf_if) bif_next; /* list of all interfaces */
|
||||
LIST_HEAD(, bpf_d) bif_dlist; /* descriptor list */
|
||||
u_int bif_dlt; /* link layer type */
|
||||
u_int bif_hdrlen; /* length of header (with padding) */
|
||||
u_int bif_hdrlen; /* length of link header */
|
||||
struct ifnet *bif_ifp; /* corresponding interface */
|
||||
struct mtx bif_mtx; /* mutex for interface */
|
||||
};
|
||||
|
@ -81,6 +81,7 @@ struct bpf_d {
|
||||
u_char bd_immediate; /* true to return on packet arrival */
|
||||
int bd_hdrcmplt; /* false to fill in src lladdr automatically */
|
||||
int bd_direction; /* select packet direction */
|
||||
int bd_tstamp; /* select time stamping function */
|
||||
int bd_feedback; /* true to feed back sent packets */
|
||||
int bd_async; /* non-zero if packet reception should generate signal */
|
||||
int bd_sig; /* signal to send upon packet reception */
|
||||
|
@ -264,6 +264,7 @@ void resettodr(void);
|
||||
|
||||
extern time_t time_second;
|
||||
extern time_t time_uptime;
|
||||
extern struct bintime boottimebin;
|
||||
extern struct timeval boottime;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user