Use hardware timestamps to report packet timestamps for SO_TIMESTAMP

and other similar socket options.

Provide new control message SCM_TIME_INFO to supply information about
timestamp.  Currently it indicates that the timestamp was
hardware-assisted and high-precision, for software timestamps the
message is not returned.  Reserved fields are added to ABI to report
additional info about it, it is expected that raw hardware clock value
might be useful for some applications.

Reviewed by:	gallatin (previous version), hselasky
Sponsored by:	Mellanox Technologies
MFC after:	2 weeks
X-Differential revision:	https://reviews.freebsd.org/D12638
This commit is contained in:
Konstantin Belousov 2017-11-07 09:46:26 +00:00
parent 3cf8254f1e
commit 06193f0be0
3 changed files with 139 additions and 18 deletions

View File

@ -1143,40 +1143,96 @@ void
ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip,
struct mbuf *m)
{
bool stamped;
stamped = false;
if ((inp->inp_socket->so_options & SO_BINTIME) ||
CHECK_SO_CT(inp->inp_socket, SO_TS_BINTIME)) {
struct bintime bt;
struct bintime boottimebin, bt;
struct timespec ts1;
bintime(&bt);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &ts1);
timespec2bintime(&ts1, &bt);
getboottimebin(&boottimebin);
bintime_add(&bt, &boottimebin);
} else {
bintime(&bt);
}
*mp = sbcreatecontrol((caddr_t)&bt, sizeof(bt),
SCM_BINTIME, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
}
if (CHECK_SO_CT(inp->inp_socket, SO_TS_REALTIME_MICRO)) {
struct bintime boottimebin, bt1;
struct timespec ts1;;
struct timeval tv;
microtime(&tv);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &ts1);
timespec2bintime(&ts1, &bt1);
getboottimebin(&boottimebin);
bintime_add(&bt1, &boottimebin);
bintime2timeval(&bt1, &tv);
} else {
microtime(&tv);
}
*mp = sbcreatecontrol((caddr_t)&tv, sizeof(tv),
SCM_TIMESTAMP, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
} else if (CHECK_SO_CT(inp->inp_socket, SO_TS_REALTIME)) {
struct timespec ts;
struct bintime boottimebin;
struct timespec ts, ts1;
nanotime(&ts);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &ts);
getboottimebin(&boottimebin);
bintime2timespec(&boottimebin, &ts1);
timespecadd(&ts, &ts1);
} else {
nanotime(&ts);
}
*mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts),
SCM_REALTIME, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
} else if (CHECK_SO_CT(inp->inp_socket, SO_TS_MONOTONIC)) {
struct timespec ts;
nanouptime(&ts);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP))
mbuf_tstmp2timespec(m, &ts);
else
nanouptime(&ts);
*mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts),
SCM_MONOTONIC, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
}
if (stamped && (m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
struct sock_timestamp_info sti;
bzero(&sti, sizeof(sti));
sti.st_info_flags = ST_INFO_HW;
if ((m->m_flags & M_TSTMP_HPREC) != 0)
sti.st_info_flags |= ST_INFO_HW_HPREC;
*mp = sbcreatecontrol((caddr_t)&sti, sizeof(sti), SCM_TIME_INFO,
SOL_SOCKET);
if (*mp != NULL)
mp = &(*mp)->m_next;
}
if (inp->inp_flags & INP_RECVDSTADDR) {

View File

@ -1221,43 +1221,97 @@ ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp,
struct bintime bt;
struct timespec ts;
} t;
struct bintime boottimebin, bt1;
struct timespec ts1;
bool stamped;
stamped = false;
switch (inp->inp_socket->so_ts_clock) {
case SO_TS_REALTIME_MICRO:
microtime(&t.tv);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &ts1);
timespec2bintime(&ts1, &bt1);
getboottimebin(&boottimebin);
bintime_add(&bt1, &boottimebin);
bintime2timeval(&bt1, &t.tv);
} else {
microtime(&t.tv);
}
*mp = sbcreatecontrol((caddr_t) &t.tv, sizeof(t.tv),
SCM_TIMESTAMP, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
break;
case SO_TS_BINTIME:
bintime(&t.bt);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &ts1);
timespec2bintime(&ts1, &t.bt);
getboottimebin(&boottimebin);
bintime_add(&t.bt, &boottimebin);
} else {
bintime(&t.bt);
}
*mp = sbcreatecontrol((caddr_t)&t.bt, sizeof(t.bt),
SCM_BINTIME, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
break;
case SO_TS_REALTIME:
nanotime(&t.ts);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP)) {
mbuf_tstmp2timespec(m, &t.ts);
getboottimebin(&boottimebin);
bintime2timespec(&boottimebin, &ts1);
timespecadd(&t.ts, &ts1);
} else {
nanotime(&t.ts);
}
*mp = sbcreatecontrol((caddr_t)&t.ts, sizeof(t.ts),
SCM_REALTIME, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
break;
case SO_TS_MONOTONIC:
nanouptime(&t.ts);
if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
M_TSTMP))
mbuf_tstmp2timespec(m, &t.ts);
else
nanouptime(&t.ts);
*mp = sbcreatecontrol((caddr_t)&t.ts, sizeof(t.ts),
SCM_MONOTONIC, SOL_SOCKET);
if (*mp)
if (*mp != NULL) {
mp = &(*mp)->m_next;
stamped = true;
}
break;
default:
panic("unknown (corrupted) so_ts_clock");
}
if (stamped && (m->m_flags & (M_PKTHDR | M_TSTMP)) ==
(M_PKTHDR | M_TSTMP)) {
struct sock_timestamp_info sti;
bzero(&sti, sizeof(sti));
sti.st_info_flags = ST_INFO_HW;
if ((m->m_flags & M_TSTMP_HPREC) != 0)
sti.st_info_flags |= ST_INFO_HW_HPREC;
*mp = sbcreatecontrol((caddr_t)&sti, sizeof(sti),
SCM_TIME_INFO, SOL_SOCKET);
if (*mp != NULL)
mp = &(*mp)->m_next;
}
}
#endif

View File

@ -563,6 +563,17 @@ struct sockcred {
#define SCM_BINTIME 0x04 /* timestamp (struct bintime) */
#define SCM_REALTIME 0x05 /* timestamp (struct timespec) */
#define SCM_MONOTONIC 0x06 /* timestamp (struct timespec) */
#define SCM_TIME_INFO 0x07 /* timestamp info */
struct sock_timestamp_info {
__uint32_t st_info_flags;
__uint32_t st_info_pad0;
__uint64_t st_info_rsv[7];
};
#define ST_INFO_HW 0x0001 /* SCM_TIMESTAMP was hw */
#define ST_INFO_HW_HPREC 0x0002 /* SCM_TIMESTAMP was hw-assisted
on entrance */
#endif
#if __BSD_VISIBLE